1*7697SMichael.Christensen@Sun.COM /* 2*7697SMichael.Christensen@Sun.COM * CDDL HEADER START 3*7697SMichael.Christensen@Sun.COM * 4*7697SMichael.Christensen@Sun.COM * The contents of this file are subject to the terms of the 5*7697SMichael.Christensen@Sun.COM * Common Development and Distribution License (the "License"). 6*7697SMichael.Christensen@Sun.COM * You may not use this file except in compliance with the License. 7*7697SMichael.Christensen@Sun.COM * 8*7697SMichael.Christensen@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7697SMichael.Christensen@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*7697SMichael.Christensen@Sun.COM * See the License for the specific language governing permissions 11*7697SMichael.Christensen@Sun.COM * and limitations under the License. 12*7697SMichael.Christensen@Sun.COM * 13*7697SMichael.Christensen@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*7697SMichael.Christensen@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7697SMichael.Christensen@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*7697SMichael.Christensen@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*7697SMichael.Christensen@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*7697SMichael.Christensen@Sun.COM * 19*7697SMichael.Christensen@Sun.COM * CDDL HEADER END 20*7697SMichael.Christensen@Sun.COM */ 21*7697SMichael.Christensen@Sun.COM 22*7697SMichael.Christensen@Sun.COM /* 23*7697SMichael.Christensen@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*7697SMichael.Christensen@Sun.COM * Use is subject to license terms. 25*7697SMichael.Christensen@Sun.COM */ 26*7697SMichael.Christensen@Sun.COM 27*7697SMichael.Christensen@Sun.COM /* 28*7697SMichael.Christensen@Sun.COM * Domain Services Module Common Code. 29*7697SMichael.Christensen@Sun.COM * 30*7697SMichael.Christensen@Sun.COM * This module is intended to be used by both Solaris and the VBSC 31*7697SMichael.Christensen@Sun.COM * module. 32*7697SMichael.Christensen@Sun.COM */ 33*7697SMichael.Christensen@Sun.COM 34*7697SMichael.Christensen@Sun.COM #include <sys/modctl.h> 35*7697SMichael.Christensen@Sun.COM #include <sys/ksynch.h> 36*7697SMichael.Christensen@Sun.COM #include <sys/taskq.h> 37*7697SMichael.Christensen@Sun.COM #include <sys/disp.h> 38*7697SMichael.Christensen@Sun.COM #include <sys/cmn_err.h> 39*7697SMichael.Christensen@Sun.COM #include <sys/note.h> 40*7697SMichael.Christensen@Sun.COM #include <sys/mach_descrip.h> 41*7697SMichael.Christensen@Sun.COM #include <sys/mdesc.h> 42*7697SMichael.Christensen@Sun.COM #include <sys/ldc.h> 43*7697SMichael.Christensen@Sun.COM #include <sys/ds.h> 44*7697SMichael.Christensen@Sun.COM #include <sys/ds_impl.h> 45*7697SMichael.Christensen@Sun.COM 46*7697SMichael.Christensen@Sun.COM #ifndef MIN 47*7697SMichael.Christensen@Sun.COM #define MIN(a, b) ((a) < (b) ? (a) : (b)) 48*7697SMichael.Christensen@Sun.COM #endif 49*7697SMichael.Christensen@Sun.COM 50*7697SMichael.Christensen@Sun.COM #define DS_DECODE_BUF_LEN 30 51*7697SMichael.Christensen@Sun.COM 52*7697SMichael.Christensen@Sun.COM /* 53*7697SMichael.Christensen@Sun.COM * All DS ports in the system 54*7697SMichael.Christensen@Sun.COM * 55*7697SMichael.Christensen@Sun.COM * The list of DS ports is read in from the MD when the DS module is 56*7697SMichael.Christensen@Sun.COM * initialized and is never modified. This eliminates the need for 57*7697SMichael.Christensen@Sun.COM * locking to access the port array itself. Access to the individual 58*7697SMichael.Christensen@Sun.COM * ports are synchronized at the port level. 59*7697SMichael.Christensen@Sun.COM */ 60*7697SMichael.Christensen@Sun.COM ds_port_t ds_ports[DS_MAX_PORTS]; 61*7697SMichael.Christensen@Sun.COM ds_portset_t ds_allports; /* all DS ports in the system */ 62*7697SMichael.Christensen@Sun.COM 63*7697SMichael.Christensen@Sun.COM /* 64*7697SMichael.Christensen@Sun.COM * Table of registered services 65*7697SMichael.Christensen@Sun.COM * 66*7697SMichael.Christensen@Sun.COM * Locking: Accesses to the table of services are synchronized using 67*7697SMichael.Christensen@Sun.COM * a mutex lock. The reader lock must be held when looking up service 68*7697SMichael.Christensen@Sun.COM * information in the table. The writer lock must be held when any 69*7697SMichael.Christensen@Sun.COM * service information is being modified. 70*7697SMichael.Christensen@Sun.COM */ 71*7697SMichael.Christensen@Sun.COM ds_svcs_t ds_svcs; 72*7697SMichael.Christensen@Sun.COM 73*7697SMichael.Christensen@Sun.COM /* 74*7697SMichael.Christensen@Sun.COM * Flag to prevent callbacks while in the middle of DS teardown. 75*7697SMichael.Christensen@Sun.COM */ 76*7697SMichael.Christensen@Sun.COM boolean_t ds_enabled = B_FALSE; /* enable/disable taskq processing */ 77*7697SMichael.Christensen@Sun.COM 78*7697SMichael.Christensen@Sun.COM /* 79*7697SMichael.Christensen@Sun.COM * Retry count and delay for LDC reads and writes 80*7697SMichael.Christensen@Sun.COM */ 81*7697SMichael.Christensen@Sun.COM #ifndef DS_DEFAULT_RETRIES 82*7697SMichael.Christensen@Sun.COM #define DS_DEFAULT_RETRIES 10000 /* number of times to retry */ 83*7697SMichael.Christensen@Sun.COM #endif 84*7697SMichael.Christensen@Sun.COM #ifndef DS_DEFAULT_DELAY 85*7697SMichael.Christensen@Sun.COM #define DS_DEFAULT_DELAY 1000 /* usecs to wait between retries */ 86*7697SMichael.Christensen@Sun.COM #endif 87*7697SMichael.Christensen@Sun.COM 88*7697SMichael.Christensen@Sun.COM static int ds_retries = DS_DEFAULT_RETRIES; 89*7697SMichael.Christensen@Sun.COM static clock_t ds_delay = DS_DEFAULT_DELAY; 90*7697SMichael.Christensen@Sun.COM 91*7697SMichael.Christensen@Sun.COM /* 92*7697SMichael.Christensen@Sun.COM * Supported versions of the DS message protocol 93*7697SMichael.Christensen@Sun.COM * 94*7697SMichael.Christensen@Sun.COM * The version array must be sorted in order from the highest 95*7697SMichael.Christensen@Sun.COM * supported version to the lowest. Support for a particular 96*7697SMichael.Christensen@Sun.COM * <major>.<minor> version implies all lower minor versions of 97*7697SMichael.Christensen@Sun.COM * that same major version are supported as well. 98*7697SMichael.Christensen@Sun.COM */ 99*7697SMichael.Christensen@Sun.COM static ds_ver_t ds_vers[] = { { 1, 0 } }; 100*7697SMichael.Christensen@Sun.COM 101*7697SMichael.Christensen@Sun.COM #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_vers[0])) 102*7697SMichael.Christensen@Sun.COM 103*7697SMichael.Christensen@Sun.COM 104*7697SMichael.Christensen@Sun.COM /* incoming message handling functions */ 105*7697SMichael.Christensen@Sun.COM typedef void (*ds_msg_handler_t)(ds_port_t *port, caddr_t buf, size_t len); 106*7697SMichael.Christensen@Sun.COM static void ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len); 107*7697SMichael.Christensen@Sun.COM static void ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len); 108*7697SMichael.Christensen@Sun.COM static void ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len); 109*7697SMichael.Christensen@Sun.COM static void ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len); 110*7697SMichael.Christensen@Sun.COM static void ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len); 111*7697SMichael.Christensen@Sun.COM static void ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len); 112*7697SMichael.Christensen@Sun.COM static void ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len); 113*7697SMichael.Christensen@Sun.COM static void ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len); 114*7697SMichael.Christensen@Sun.COM static void ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len); 115*7697SMichael.Christensen@Sun.COM static void ds_handle_data(ds_port_t *port, caddr_t buf, size_t len); 116*7697SMichael.Christensen@Sun.COM static void ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len); 117*7697SMichael.Christensen@Sun.COM 118*7697SMichael.Christensen@Sun.COM /* 119*7697SMichael.Christensen@Sun.COM * DS Message Handler Dispatch Table 120*7697SMichael.Christensen@Sun.COM * 121*7697SMichael.Christensen@Sun.COM * A table used to dispatch all incoming messages. This table 122*7697SMichael.Christensen@Sun.COM * contains handlers for all the fixed message types, as well as 123*7697SMichael.Christensen@Sun.COM * the the messages defined in the 1.0 version of the DS protocol. 124*7697SMichael.Christensen@Sun.COM * The handlers are indexed based on the DS header msg_type values 125*7697SMichael.Christensen@Sun.COM */ 126*7697SMichael.Christensen@Sun.COM static const ds_msg_handler_t ds_msg_handlers[] = { 127*7697SMichael.Christensen@Sun.COM ds_handle_init_req, /* DS_INIT_REQ */ 128*7697SMichael.Christensen@Sun.COM ds_handle_init_ack, /* DS_INIT_ACK */ 129*7697SMichael.Christensen@Sun.COM ds_handle_init_nack, /* DS_INIT_NACK */ 130*7697SMichael.Christensen@Sun.COM ds_handle_reg_req, /* DS_REG_REQ */ 131*7697SMichael.Christensen@Sun.COM ds_handle_reg_ack, /* DS_REG_ACK */ 132*7697SMichael.Christensen@Sun.COM ds_handle_reg_nack, /* DS_REG_NACK */ 133*7697SMichael.Christensen@Sun.COM ds_handle_unreg_req, /* DS_UNREG */ 134*7697SMichael.Christensen@Sun.COM ds_handle_unreg_ack, /* DS_UNREG_ACK */ 135*7697SMichael.Christensen@Sun.COM ds_handle_unreg_nack, /* DS_UNREG_NACK */ 136*7697SMichael.Christensen@Sun.COM ds_handle_data, /* DS_DATA */ 137*7697SMichael.Christensen@Sun.COM ds_handle_nack /* DS_NACK */ 138*7697SMichael.Christensen@Sun.COM }; 139*7697SMichael.Christensen@Sun.COM 140*7697SMichael.Christensen@Sun.COM 141*7697SMichael.Christensen@Sun.COM 142*7697SMichael.Christensen@Sun.COM /* initialization functions */ 143*7697SMichael.Christensen@Sun.COM static int ds_ldc_init(ds_port_t *port); 144*7697SMichael.Christensen@Sun.COM 145*7697SMichael.Christensen@Sun.COM /* event processing functions */ 146*7697SMichael.Christensen@Sun.COM static uint_t ds_ldc_cb(uint64_t event, caddr_t arg); 147*7697SMichael.Christensen@Sun.COM static int ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep); 148*7697SMichael.Christensen@Sun.COM static void ds_handle_up_event(ds_port_t *port); 149*7697SMichael.Christensen@Sun.COM static void ds_handle_down_reset_events(ds_port_t *port); 150*7697SMichael.Christensen@Sun.COM static void ds_handle_recv(void *arg); 151*7697SMichael.Christensen@Sun.COM static void ds_dispatch_event(void *arg); 152*7697SMichael.Christensen@Sun.COM 153*7697SMichael.Christensen@Sun.COM /* message sending functions */ 154*7697SMichael.Christensen@Sun.COM static int ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen); 155*7697SMichael.Christensen@Sun.COM static int ds_send_reg_req(ds_svc_t *svc, ds_port_t *port); 156*7697SMichael.Christensen@Sun.COM static void ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl); 157*7697SMichael.Christensen@Sun.COM static void ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl); 158*7697SMichael.Christensen@Sun.COM 159*7697SMichael.Christensen@Sun.COM /* walker functions */ 160*7697SMichael.Christensen@Sun.COM static int ds_svc_isfree(ds_svc_t *svc, void *arg); 161*7697SMichael.Christensen@Sun.COM static int ds_svc_unregister(ds_svc_t *svc, void *arg); 162*7697SMichael.Christensen@Sun.COM static int ds_svc_port_up(ds_svc_t *svc, void *arg); 163*7697SMichael.Christensen@Sun.COM 164*7697SMichael.Christensen@Sun.COM /* service utilities */ 165*7697SMichael.Christensen@Sun.COM static void ds_reset_svc(ds_svc_t *svc, ds_port_t *port); 166*7697SMichael.Christensen@Sun.COM static int ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port); 167*7697SMichael.Christensen@Sun.COM 168*7697SMichael.Christensen@Sun.COM /* port utilities */ 169*7697SMichael.Christensen@Sun.COM static void ds_port_reset(ds_port_t *port); 170*7697SMichael.Christensen@Sun.COM static ldc_status_t ds_update_ldc_state(ds_port_t *port); 171*7697SMichael.Christensen@Sun.COM 172*7697SMichael.Christensen@Sun.COM /* misc utilities */ 173*7697SMichael.Christensen@Sun.COM static void min_max_versions(int num_versions, ds_ver_t *sup_versionsp, 174*7697SMichael.Christensen@Sun.COM uint16_t *min_major, uint16_t *max_major); 175*7697SMichael.Christensen@Sun.COM 176*7697SMichael.Christensen@Sun.COM /* debug */ 177*7697SMichael.Christensen@Sun.COM static char *decode_ldc_events(uint64_t event, char *buf); 178*7697SMichael.Christensen@Sun.COM 179*7697SMichael.Christensen@Sun.COM /* loopback */ 180*7697SMichael.Christensen@Sun.COM static void ds_loopback_register(ds_svc_hdl_t hdl); 181*7697SMichael.Christensen@Sun.COM static void ds_loopback_unregister(ds_svc_hdl_t hdl); 182*7697SMichael.Christensen@Sun.COM static void ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen); 183*7697SMichael.Christensen@Sun.COM static int ds_loopback_set_svc(ds_svc_t *svc, ds_svc_hdl_t lb_hdl); 184*7697SMichael.Christensen@Sun.COM 185*7697SMichael.Christensen@Sun.COM /* client handling */ 186*7697SMichael.Christensen@Sun.COM static int i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 187*7697SMichael.Christensen@Sun.COM uint_t maxhdls); 188*7697SMichael.Christensen@Sun.COM static ds_svc_t *ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl, 189*7697SMichael.Christensen@Sun.COM ds_port_t *port); 190*7697SMichael.Christensen@Sun.COM static ds_svc_t *ds_find_svc_by_id_port(char *svc_id, int is_client, 191*7697SMichael.Christensen@Sun.COM ds_port_t *port); 192*7697SMichael.Christensen@Sun.COM static ds_svc_t *ds_svc_clone(ds_svc_t *svc); 193*7697SMichael.Christensen@Sun.COM static void ds_portset_del_active_clients(char *service, ds_portset_t *portsp); 194*7697SMichael.Christensen@Sun.COM static void ds_check_for_dup_services(ds_svc_t *svc); 195*7697SMichael.Christensen@Sun.COM static void ds_delete_svc_entry(ds_svc_t *svc); 196*7697SMichael.Christensen@Sun.COM 197*7697SMichael.Christensen@Sun.COM char * 198*7697SMichael.Christensen@Sun.COM ds_strdup(char *str) 199*7697SMichael.Christensen@Sun.COM { 200*7697SMichael.Christensen@Sun.COM char *newstr; 201*7697SMichael.Christensen@Sun.COM 202*7697SMichael.Christensen@Sun.COM newstr = DS_MALLOC(strlen(str) + 1); 203*7697SMichael.Christensen@Sun.COM (void) strcpy(newstr, str); 204*7697SMichael.Christensen@Sun.COM return (newstr); 205*7697SMichael.Christensen@Sun.COM } 206*7697SMichael.Christensen@Sun.COM 207*7697SMichael.Christensen@Sun.COM void 208*7697SMichael.Christensen@Sun.COM ds_common_init(void) 209*7697SMichael.Christensen@Sun.COM { 210*7697SMichael.Christensen@Sun.COM /* Validate version table */ 211*7697SMichael.Christensen@Sun.COM ASSERT(ds_vers_isvalid(ds_vers, DS_NUM_VER) == DS_VERS_OK); 212*7697SMichael.Christensen@Sun.COM 213*7697SMichael.Christensen@Sun.COM /* Initialize services table */ 214*7697SMichael.Christensen@Sun.COM ds_init_svcs_tbl(DS_MAXSVCS_INIT); 215*7697SMichael.Christensen@Sun.COM 216*7697SMichael.Christensen@Sun.COM /* enable callback processing */ 217*7697SMichael.Christensen@Sun.COM ds_enabled = B_TRUE; 218*7697SMichael.Christensen@Sun.COM } 219*7697SMichael.Christensen@Sun.COM 220*7697SMichael.Christensen@Sun.COM /* BEGIN LDC SUPPORT FUNCTIONS */ 221*7697SMichael.Christensen@Sun.COM 222*7697SMichael.Christensen@Sun.COM static char * 223*7697SMichael.Christensen@Sun.COM decode_ldc_events(uint64_t event, char *buf) 224*7697SMichael.Christensen@Sun.COM { 225*7697SMichael.Christensen@Sun.COM buf[0] = 0; 226*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_DOWN) (void) strcat(buf, " DOWN"); 227*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_RESET) (void) strcat(buf, " RESET"); 228*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_UP) (void) strcat(buf, " UP"); 229*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_READ) (void) strcat(buf, " READ"); 230*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_WRITE) (void) strcat(buf, " WRITE"); 231*7697SMichael.Christensen@Sun.COM return (buf); 232*7697SMichael.Christensen@Sun.COM } 233*7697SMichael.Christensen@Sun.COM 234*7697SMichael.Christensen@Sun.COM static ldc_status_t 235*7697SMichael.Christensen@Sun.COM ds_update_ldc_state(ds_port_t *port) 236*7697SMichael.Christensen@Sun.COM { 237*7697SMichael.Christensen@Sun.COM ldc_status_t ldc_state; 238*7697SMichael.Christensen@Sun.COM int rv; 239*7697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 240*7697SMichael.Christensen@Sun.COM 241*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 242*7697SMichael.Christensen@Sun.COM 243*7697SMichael.Christensen@Sun.COM /* 244*7697SMichael.Christensen@Sun.COM * Read status and update ldc state info in port structure. 245*7697SMichael.Christensen@Sun.COM */ 246*7697SMichael.Christensen@Sun.COM if ((rv = ldc_status(port->ldc.hdl, &ldc_state)) != 0) { 247*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_status error: %s" DS_EOL, 248*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 249*7697SMichael.Christensen@Sun.COM ldc_state = port->ldc.state; 250*7697SMichael.Christensen@Sun.COM } else { 251*7697SMichael.Christensen@Sun.COM port->ldc.state = ldc_state; 252*7697SMichael.Christensen@Sun.COM } 253*7697SMichael.Christensen@Sun.COM 254*7697SMichael.Christensen@Sun.COM return (ldc_state); 255*7697SMichael.Christensen@Sun.COM } 256*7697SMichael.Christensen@Sun.COM 257*7697SMichael.Christensen@Sun.COM static void 258*7697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(ds_port_t *port) 259*7697SMichael.Christensen@Sun.COM { 260*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port), 261*7697SMichael.Christensen@Sun.COM __func__); 262*7697SMichael.Christensen@Sun.COM 263*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 264*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 265*7697SMichael.Christensen@Sun.COM 266*7697SMichael.Christensen@Sun.COM ds_sys_drain_events(port); 267*7697SMichael.Christensen@Sun.COM 268*7697SMichael.Christensen@Sun.COM (void) ds_update_ldc_state(port); 269*7697SMichael.Christensen@Sun.COM 270*7697SMichael.Christensen@Sun.COM /* reset the port state */ 271*7697SMichael.Christensen@Sun.COM ds_port_reset(port); 272*7697SMichael.Christensen@Sun.COM 273*7697SMichael.Christensen@Sun.COM /* acknowledge the reset */ 274*7697SMichael.Christensen@Sun.COM (void) ldc_up(port->ldc.hdl); 275*7697SMichael.Christensen@Sun.COM 276*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 277*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 278*7697SMichael.Christensen@Sun.COM 279*7697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 280*7697SMichael.Christensen@Sun.COM 281*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 282*7697SMichael.Christensen@Sun.COM } 283*7697SMichael.Christensen@Sun.COM 284*7697SMichael.Christensen@Sun.COM static void 285*7697SMichael.Christensen@Sun.COM ds_handle_up_event(ds_port_t *port) 286*7697SMichael.Christensen@Sun.COM { 287*7697SMichael.Christensen@Sun.COM ldc_status_t ldc_state; 288*7697SMichael.Christensen@Sun.COM 289*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port), 290*7697SMichael.Christensen@Sun.COM __func__); 291*7697SMichael.Christensen@Sun.COM 292*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 293*7697SMichael.Christensen@Sun.COM 294*7697SMichael.Christensen@Sun.COM ldc_state = ds_update_ldc_state(port); 295*7697SMichael.Christensen@Sun.COM 296*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 297*7697SMichael.Christensen@Sun.COM 298*7697SMichael.Christensen@Sun.COM if ((ldc_state == LDC_UP) && IS_DS_PORT(port)) { 299*7697SMichael.Christensen@Sun.COM /* 300*7697SMichael.Christensen@Sun.COM * Initiate the handshake. 301*7697SMichael.Christensen@Sun.COM */ 302*7697SMichael.Christensen@Sun.COM ds_send_init_req(port); 303*7697SMichael.Christensen@Sun.COM } 304*7697SMichael.Christensen@Sun.COM 305*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 306*7697SMichael.Christensen@Sun.COM } 307*7697SMichael.Christensen@Sun.COM 308*7697SMichael.Christensen@Sun.COM static uint_t 309*7697SMichael.Christensen@Sun.COM ds_ldc_cb(uint64_t event, caddr_t arg) 310*7697SMichael.Christensen@Sun.COM { 311*7697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 312*7697SMichael.Christensen@Sun.COM char evstring[DS_DECODE_BUF_LEN]; 313*7697SMichael.Christensen@Sun.COM 314*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: %s event (%llx) received" DS_EOL, 315*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, decode_ldc_events(event, evstring), 316*7697SMichael.Christensen@Sun.COM (u_longlong_t)event); 317*7697SMichael.Christensen@Sun.COM 318*7697SMichael.Christensen@Sun.COM if (!ds_enabled) { 319*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: callback handling is disabled" 320*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__); 321*7697SMichael.Christensen@Sun.COM return (LDC_SUCCESS); 322*7697SMichael.Christensen@Sun.COM } 323*7697SMichael.Christensen@Sun.COM 324*7697SMichael.Christensen@Sun.COM if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) { 325*7697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 326*7697SMichael.Christensen@Sun.COM goto done; 327*7697SMichael.Christensen@Sun.COM } 328*7697SMichael.Christensen@Sun.COM 329*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_UP) { 330*7697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 331*7697SMichael.Christensen@Sun.COM } 332*7697SMichael.Christensen@Sun.COM 333*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_READ) { 334*7697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 335*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: LDC READ event while " 336*7697SMichael.Christensen@Sun.COM "port not up" DS_EOL, PORTID(port), __func__); 337*7697SMichael.Christensen@Sun.COM goto done; 338*7697SMichael.Christensen@Sun.COM } 339*7697SMichael.Christensen@Sun.COM 340*7697SMichael.Christensen@Sun.COM if (ds_sys_dispatch_func(ds_handle_recv, port)) { 341*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: error initiating LDC READ " 342*7697SMichael.Christensen@Sun.COM " event", PORTID(port)); 343*7697SMichael.Christensen@Sun.COM } 344*7697SMichael.Christensen@Sun.COM } 345*7697SMichael.Christensen@Sun.COM 346*7697SMichael.Christensen@Sun.COM if (event & LDC_EVT_WRITE) { 347*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: LDC WRITE event received, " 348*7697SMichael.Christensen@Sun.COM "not supported" DS_EOL, PORTID(port), __func__); 349*7697SMichael.Christensen@Sun.COM } 350*7697SMichael.Christensen@Sun.COM 351*7697SMichael.Christensen@Sun.COM if (event & ~(LDC_EVT_UP | LDC_EVT_READ)) { 352*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: Unexpected LDC event received: " 353*7697SMichael.Christensen@Sun.COM "0x%llx" DS_EOL, PORTID(port), __func__, 354*7697SMichael.Christensen@Sun.COM (u_longlong_t)event); 355*7697SMichael.Christensen@Sun.COM } 356*7697SMichael.Christensen@Sun.COM done: 357*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 358*7697SMichael.Christensen@Sun.COM 359*7697SMichael.Christensen@Sun.COM return (LDC_SUCCESS); 360*7697SMichael.Christensen@Sun.COM } 361*7697SMichael.Christensen@Sun.COM 362*7697SMichael.Christensen@Sun.COM static int 363*7697SMichael.Christensen@Sun.COM ds_ldc_init(ds_port_t *port) 364*7697SMichael.Christensen@Sun.COM { 365*7697SMichael.Christensen@Sun.COM int rv; 366*7697SMichael.Christensen@Sun.COM ldc_attr_t ldc_attr; 367*7697SMichael.Christensen@Sun.COM caddr_t ldc_cb_arg = (caddr_t)port; 368*7697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 369*7697SMichael.Christensen@Sun.COM 370*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 371*7697SMichael.Christensen@Sun.COM 372*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%lld" DS_EOL, 373*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)port->ldc.id); 374*7697SMichael.Christensen@Sun.COM 375*7697SMichael.Christensen@Sun.COM ldc_attr.devclass = LDC_DEV_GENERIC; 376*7697SMichael.Christensen@Sun.COM ldc_attr.instance = 0; 377*7697SMichael.Christensen@Sun.COM ldc_attr.mode = LDC_MODE_RELIABLE; 378*7697SMichael.Christensen@Sun.COM ldc_attr.mtu = DS_STREAM_MTU; 379*7697SMichael.Christensen@Sun.COM 380*7697SMichael.Christensen@Sun.COM if ((rv = ldc_init(port->ldc.id, &ldc_attr, &port->ldc.hdl)) != 0) { 381*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_id: %lx, ldc_init error: %s" 382*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, port->ldc.id, 383*7697SMichael.Christensen@Sun.COM ds_errno_to_str(rv, ebuf)); 384*7697SMichael.Christensen@Sun.COM return (rv); 385*7697SMichael.Christensen@Sun.COM } 386*7697SMichael.Christensen@Sun.COM 387*7697SMichael.Christensen@Sun.COM rv = ldc_reg_callback(port->ldc.hdl, ds_ldc_cb, ldc_cb_arg); 388*7697SMichael.Christensen@Sun.COM if (rv != 0) { 389*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_reg_callback error: %s" 390*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 391*7697SMichael.Christensen@Sun.COM return (rv); 392*7697SMichael.Christensen@Sun.COM } 393*7697SMichael.Christensen@Sun.COM 394*7697SMichael.Christensen@Sun.COM ds_sys_ldc_init(port); 395*7697SMichael.Christensen@Sun.COM return (0); 396*7697SMichael.Christensen@Sun.COM } 397*7697SMichael.Christensen@Sun.COM 398*7697SMichael.Christensen@Sun.COM int 399*7697SMichael.Christensen@Sun.COM ds_ldc_fini(ds_port_t *port) 400*7697SMichael.Christensen@Sun.COM { 401*7697SMichael.Christensen@Sun.COM int rv; 402*7697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 403*7697SMichael.Christensen@Sun.COM 404*7697SMichael.Christensen@Sun.COM ASSERT(port->state >= DS_PORT_LDC_INIT); 405*7697SMichael.Christensen@Sun.COM 406*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%ld" DS_EOL, PORTID(port), 407*7697SMichael.Christensen@Sun.COM __func__, port->ldc.id); 408*7697SMichael.Christensen@Sun.COM 409*7697SMichael.Christensen@Sun.COM if ((rv = ldc_close(port->ldc.hdl)) != 0) { 410*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_close error: %s" DS_EOL, 411*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 412*7697SMichael.Christensen@Sun.COM return (rv); 413*7697SMichael.Christensen@Sun.COM } 414*7697SMichael.Christensen@Sun.COM 415*7697SMichael.Christensen@Sun.COM if ((rv = ldc_unreg_callback(port->ldc.hdl)) != 0) { 416*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_unreg_callback error: %s" 417*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 418*7697SMichael.Christensen@Sun.COM return (rv); 419*7697SMichael.Christensen@Sun.COM } 420*7697SMichael.Christensen@Sun.COM 421*7697SMichael.Christensen@Sun.COM if ((rv = ldc_fini(port->ldc.hdl)) != 0) { 422*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_fini error: %s" DS_EOL, 423*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 424*7697SMichael.Christensen@Sun.COM return (rv); 425*7697SMichael.Christensen@Sun.COM } 426*7697SMichael.Christensen@Sun.COM 427*7697SMichael.Christensen@Sun.COM return (rv); 428*7697SMichael.Christensen@Sun.COM } 429*7697SMichael.Christensen@Sun.COM 430*7697SMichael.Christensen@Sun.COM /* 431*7697SMichael.Christensen@Sun.COM * Attempt to read a specified number of bytes from a particular LDC. 432*7697SMichael.Christensen@Sun.COM * Returns zero for success or the return code from the LDC read on 433*7697SMichael.Christensen@Sun.COM * failure. The actual number of bytes read from the LDC is returned 434*7697SMichael.Christensen@Sun.COM * in the size parameter. 435*7697SMichael.Christensen@Sun.COM */ 436*7697SMichael.Christensen@Sun.COM static int 437*7697SMichael.Christensen@Sun.COM ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep) 438*7697SMichael.Christensen@Sun.COM { 439*7697SMichael.Christensen@Sun.COM int rv = 0; 440*7697SMichael.Christensen@Sun.COM size_t bytes_req = *sizep; 441*7697SMichael.Christensen@Sun.COM size_t bytes_left = bytes_req; 442*7697SMichael.Christensen@Sun.COM size_t nbytes; 443*7697SMichael.Christensen@Sun.COM int retry_count = 0; 444*7697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 445*7697SMichael.Christensen@Sun.COM 446*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->rcv_lock)); 447*7697SMichael.Christensen@Sun.COM 448*7697SMichael.Christensen@Sun.COM *sizep = 0; 449*7697SMichael.Christensen@Sun.COM 450*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: attempting to read %ld bytes" DS_EOL, 451*7697SMichael.Christensen@Sun.COM PORTID(port), bytes_req); 452*7697SMichael.Christensen@Sun.COM 453*7697SMichael.Christensen@Sun.COM while (bytes_left > 0) { 454*7697SMichael.Christensen@Sun.COM 455*7697SMichael.Christensen@Sun.COM nbytes = bytes_left; 456*7697SMichael.Christensen@Sun.COM 457*7697SMichael.Christensen@Sun.COM if ((rv = ldc_read(port->ldc.hdl, msgp, &nbytes)) != 0) { 458*7697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 459*7697SMichael.Christensen@Sun.COM break; 460*7697SMichael.Christensen@Sun.COM } else if (rv != EAGAIN) { 461*7697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "ds@%lx: %s: %s" DS_EOL, 462*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, 463*7697SMichael.Christensen@Sun.COM ds_errno_to_str(rv, ebuf)); 464*7697SMichael.Christensen@Sun.COM break; 465*7697SMichael.Christensen@Sun.COM } 466*7697SMichael.Christensen@Sun.COM } else { 467*7697SMichael.Christensen@Sun.COM if (nbytes != 0) { 468*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: " 469*7697SMichael.Christensen@Sun.COM "read %ld bytes, %d retries" DS_EOL, 470*7697SMichael.Christensen@Sun.COM PORTID(port), nbytes, retry_count); 471*7697SMichael.Christensen@Sun.COM 472*7697SMichael.Christensen@Sun.COM *sizep += nbytes; 473*7697SMichael.Christensen@Sun.COM msgp += nbytes; 474*7697SMichael.Christensen@Sun.COM bytes_left -= nbytes; 475*7697SMichael.Christensen@Sun.COM 476*7697SMichael.Christensen@Sun.COM /* reset counter on a successful read */ 477*7697SMichael.Christensen@Sun.COM retry_count = 0; 478*7697SMichael.Christensen@Sun.COM continue; 479*7697SMichael.Christensen@Sun.COM } 480*7697SMichael.Christensen@Sun.COM 481*7697SMichael.Christensen@Sun.COM /* 482*7697SMichael.Christensen@Sun.COM * No data was read. Check if this is the 483*7697SMichael.Christensen@Sun.COM * first attempt. If so, just return since 484*7697SMichael.Christensen@Sun.COM * nothing has been read yet. 485*7697SMichael.Christensen@Sun.COM */ 486*7697SMichael.Christensen@Sun.COM if (bytes_left == bytes_req) { 487*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: read zero bytes, " 488*7697SMichael.Christensen@Sun.COM " no data available" DS_EOL, PORTID(port)); 489*7697SMichael.Christensen@Sun.COM break; 490*7697SMichael.Christensen@Sun.COM } 491*7697SMichael.Christensen@Sun.COM } 492*7697SMichael.Christensen@Sun.COM 493*7697SMichael.Christensen@Sun.COM /* 494*7697SMichael.Christensen@Sun.COM * A retry is necessary because the read returned 495*7697SMichael.Christensen@Sun.COM * EAGAIN, or a zero length read occurred after 496*7697SMichael.Christensen@Sun.COM * reading a partial message. 497*7697SMichael.Christensen@Sun.COM */ 498*7697SMichael.Christensen@Sun.COM if (retry_count++ >= ds_retries) { 499*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: timed out waiting for " 500*7697SMichael.Christensen@Sun.COM "message" DS_EOL, PORTID(port)); 501*7697SMichael.Christensen@Sun.COM break; 502*7697SMichael.Christensen@Sun.COM } 503*7697SMichael.Christensen@Sun.COM 504*7697SMichael.Christensen@Sun.COM drv_usecwait(ds_delay); 505*7697SMichael.Christensen@Sun.COM } 506*7697SMichael.Christensen@Sun.COM 507*7697SMichael.Christensen@Sun.COM return (rv); 508*7697SMichael.Christensen@Sun.COM } 509*7697SMichael.Christensen@Sun.COM 510*7697SMichael.Christensen@Sun.COM static void 511*7697SMichael.Christensen@Sun.COM ds_handle_recv(void *arg) 512*7697SMichael.Christensen@Sun.COM { 513*7697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 514*7697SMichael.Christensen@Sun.COM char *hbuf; 515*7697SMichael.Christensen@Sun.COM size_t msglen; 516*7697SMichael.Christensen@Sun.COM size_t read_size; 517*7697SMichael.Christensen@Sun.COM boolean_t hasdata; 518*7697SMichael.Christensen@Sun.COM ds_hdr_t hdr; 519*7697SMichael.Christensen@Sun.COM uint8_t *msg; 520*7697SMichael.Christensen@Sun.COM char *currp; 521*7697SMichael.Christensen@Sun.COM int rv; 522*7697SMichael.Christensen@Sun.COM ds_event_t *devent; 523*7697SMichael.Christensen@Sun.COM 524*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s..." DS_EOL, PORTID(port), __func__); 525*7697SMichael.Christensen@Sun.COM 526*7697SMichael.Christensen@Sun.COM /* 527*7697SMichael.Christensen@Sun.COM * Read messages from the channel until there are none 528*7697SMichael.Christensen@Sun.COM * pending. Valid messages are dispatched to be handled 529*7697SMichael.Christensen@Sun.COM * by a separate thread while any malformed messages are 530*7697SMichael.Christensen@Sun.COM * dropped. 531*7697SMichael.Christensen@Sun.COM */ 532*7697SMichael.Christensen@Sun.COM 533*7697SMichael.Christensen@Sun.COM mutex_enter(&port->rcv_lock); 534*7697SMichael.Christensen@Sun.COM 535*7697SMichael.Christensen@Sun.COM while (((rv = ldc_chkq(port->ldc.hdl, &hasdata)) == 0) && hasdata) { 536*7697SMichael.Christensen@Sun.COM 537*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: %s: reading next message" DS_EOL, 538*7697SMichael.Christensen@Sun.COM PORTID(port), __func__); 539*7697SMichael.Christensen@Sun.COM 540*7697SMichael.Christensen@Sun.COM /* 541*7697SMichael.Christensen@Sun.COM * Read in the next message. 542*7697SMichael.Christensen@Sun.COM */ 543*7697SMichael.Christensen@Sun.COM hbuf = (char *)&hdr; 544*7697SMichael.Christensen@Sun.COM bzero(hbuf, DS_HDR_SZ); 545*7697SMichael.Christensen@Sun.COM read_size = DS_HDR_SZ; 546*7697SMichael.Christensen@Sun.COM currp = hbuf; 547*7697SMichael.Christensen@Sun.COM 548*7697SMichael.Christensen@Sun.COM /* read in the message header */ 549*7697SMichael.Christensen@Sun.COM if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) { 550*7697SMichael.Christensen@Sun.COM break; 551*7697SMichael.Christensen@Sun.COM } 552*7697SMichael.Christensen@Sun.COM 553*7697SMichael.Christensen@Sun.COM if (read_size < DS_HDR_SZ) { 554*7697SMichael.Christensen@Sun.COM /* 555*7697SMichael.Christensen@Sun.COM * A zero length read is a valid signal that 556*7697SMichael.Christensen@Sun.COM * there is no data left on the channel. 557*7697SMichael.Christensen@Sun.COM */ 558*7697SMichael.Christensen@Sun.COM if (read_size != 0) { 559*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: invalid message " 560*7697SMichael.Christensen@Sun.COM "length, received %ld bytes, expected %ld" 561*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), read_size, DS_HDR_SZ); 562*7697SMichael.Christensen@Sun.COM } 563*7697SMichael.Christensen@Sun.COM continue; 564*7697SMichael.Christensen@Sun.COM } 565*7697SMichael.Christensen@Sun.COM 566*7697SMichael.Christensen@Sun.COM /* get payload size and allocate a buffer */ 567*7697SMichael.Christensen@Sun.COM read_size = ((ds_hdr_t *)hbuf)->payload_len; 568*7697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + read_size; 569*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 570*7697SMichael.Christensen@Sun.COM if (!msg) { 571*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "Memory allocation failed attempting " 572*7697SMichael.Christensen@Sun.COM " to allocate %d bytes." DS_EOL, (int)msglen); 573*7697SMichael.Christensen@Sun.COM continue; 574*7697SMichael.Christensen@Sun.COM } 575*7697SMichael.Christensen@Sun.COM 576*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: %s: message payload len %d" DS_EOL, 577*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, (int)read_size); 578*7697SMichael.Christensen@Sun.COM 579*7697SMichael.Christensen@Sun.COM /* move message header into buffer */ 580*7697SMichael.Christensen@Sun.COM (void) memcpy(msg, hbuf, DS_HDR_SZ); 581*7697SMichael.Christensen@Sun.COM currp = (char *)(msg) + DS_HDR_SZ; 582*7697SMichael.Christensen@Sun.COM 583*7697SMichael.Christensen@Sun.COM /* read in the message body */ 584*7697SMichael.Christensen@Sun.COM if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) { 585*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 586*7697SMichael.Christensen@Sun.COM break; 587*7697SMichael.Christensen@Sun.COM } 588*7697SMichael.Christensen@Sun.COM 589*7697SMichael.Christensen@Sun.COM /* validate the size of the message */ 590*7697SMichael.Christensen@Sun.COM if ((DS_HDR_SZ + read_size) != msglen) { 591*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: invalid message length, " 592*7697SMichael.Christensen@Sun.COM "received %ld bytes, expected %ld" DS_EOL, 593*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, (DS_HDR_SZ + read_size), 594*7697SMichael.Christensen@Sun.COM msglen); 595*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 596*7697SMichael.Christensen@Sun.COM continue; 597*7697SMichael.Christensen@Sun.COM } 598*7697SMichael.Christensen@Sun.COM 599*7697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen); 600*7697SMichael.Christensen@Sun.COM 601*7697SMichael.Christensen@Sun.COM /* 602*7697SMichael.Christensen@Sun.COM * Send the message for processing, and store it 603*7697SMichael.Christensen@Sun.COM * in the log. The memory is deallocated only when 604*7697SMichael.Christensen@Sun.COM * the message is removed from the log. 605*7697SMichael.Christensen@Sun.COM */ 606*7697SMichael.Christensen@Sun.COM 607*7697SMichael.Christensen@Sun.COM devent = DS_MALLOC(sizeof (ds_event_t)); 608*7697SMichael.Christensen@Sun.COM devent->port = port; 609*7697SMichael.Christensen@Sun.COM devent->buf = (char *)msg; 610*7697SMichael.Christensen@Sun.COM devent->buflen = msglen; 611*7697SMichael.Christensen@Sun.COM 612*7697SMichael.Christensen@Sun.COM /* log the message */ 613*7697SMichael.Christensen@Sun.COM (void) ds_log_add_msg(DS_LOG_IN(port->id), msg, msglen); 614*7697SMichael.Christensen@Sun.COM 615*7697SMichael.Christensen@Sun.COM if (ds_sys_dispatch_func(ds_dispatch_event, devent)) { 616*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: error initiating " 617*7697SMichael.Christensen@Sun.COM "event handler", PORTID(port)); 618*7697SMichael.Christensen@Sun.COM DS_FREE(devent, sizeof (ds_event_t)); 619*7697SMichael.Christensen@Sun.COM } 620*7697SMichael.Christensen@Sun.COM } 621*7697SMichael.Christensen@Sun.COM 622*7697SMichael.Christensen@Sun.COM mutex_exit(&port->rcv_lock); 623*7697SMichael.Christensen@Sun.COM 624*7697SMichael.Christensen@Sun.COM /* handle connection reset errors returned from ds_recv_msg */ 625*7697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 626*7697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 627*7697SMichael.Christensen@Sun.COM } 628*7697SMichael.Christensen@Sun.COM 629*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s done" DS_EOL, PORTID(port), __func__); 630*7697SMichael.Christensen@Sun.COM } 631*7697SMichael.Christensen@Sun.COM 632*7697SMichael.Christensen@Sun.COM static void 633*7697SMichael.Christensen@Sun.COM ds_dispatch_event(void *arg) 634*7697SMichael.Christensen@Sun.COM { 635*7697SMichael.Christensen@Sun.COM ds_event_t *event = (ds_event_t *)arg; 636*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 637*7697SMichael.Christensen@Sun.COM ds_port_t *port; 638*7697SMichael.Christensen@Sun.COM 639*7697SMichael.Christensen@Sun.COM port = event->port; 640*7697SMichael.Christensen@Sun.COM 641*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)event->buf; 642*7697SMichael.Christensen@Sun.COM 643*7697SMichael.Christensen@Sun.COM if (DS_MSG_TYPE_VALID(hdr->msg_type)) { 644*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: dispatch_event: msg_type=%d" DS_EOL, 645*7697SMichael.Christensen@Sun.COM PORTID(port), hdr->msg_type); 646*7697SMichael.Christensen@Sun.COM 647*7697SMichael.Christensen@Sun.COM (*ds_msg_handlers[hdr->msg_type])(port, event->buf, 648*7697SMichael.Christensen@Sun.COM event->buflen); 649*7697SMichael.Christensen@Sun.COM } else { 650*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: dispatch_event: invalid msg " 651*7697SMichael.Christensen@Sun.COM "type (%d)" DS_EOL, PORTID(port), hdr->msg_type); 652*7697SMichael.Christensen@Sun.COM } 653*7697SMichael.Christensen@Sun.COM 654*7697SMichael.Christensen@Sun.COM DS_FREE(event->buf, event->buflen); 655*7697SMichael.Christensen@Sun.COM DS_FREE(event, sizeof (ds_event_t)); 656*7697SMichael.Christensen@Sun.COM } 657*7697SMichael.Christensen@Sun.COM 658*7697SMichael.Christensen@Sun.COM int 659*7697SMichael.Christensen@Sun.COM ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen) 660*7697SMichael.Christensen@Sun.COM { 661*7697SMichael.Christensen@Sun.COM int rv; 662*7697SMichael.Christensen@Sun.COM caddr_t currp = msg; 663*7697SMichael.Christensen@Sun.COM size_t amt_left = msglen; 664*7697SMichael.Christensen@Sun.COM int loopcnt = 0; 665*7697SMichael.Christensen@Sun.COM 666*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s msglen: %ld" DS_EOL, PORTID(port), 667*7697SMichael.Christensen@Sun.COM __func__, msglen); 668*7697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen); 669*7697SMichael.Christensen@Sun.COM 670*7697SMichael.Christensen@Sun.COM /* 671*7697SMichael.Christensen@Sun.COM * Ensure that no other messages can be sent on this port by holding 672*7697SMichael.Christensen@Sun.COM * the tx_lock mutex in case the write doesn't get sent with one write. 673*7697SMichael.Christensen@Sun.COM * This guarantees that the message doesn't become fragmented. 674*7697SMichael.Christensen@Sun.COM */ 675*7697SMichael.Christensen@Sun.COM mutex_enter(&port->tx_lock); 676*7697SMichael.Christensen@Sun.COM 677*7697SMichael.Christensen@Sun.COM do { 678*7697SMichael.Christensen@Sun.COM if ((rv = ldc_write(port->ldc.hdl, currp, &msglen)) != 0) { 679*7697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 680*7697SMichael.Christensen@Sun.COM mutex_exit(&port->tx_lock); 681*7697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 682*7697SMichael.Christensen@Sun.COM return (rv); 683*7697SMichael.Christensen@Sun.COM } else if ((rv == EWOULDBLOCK) && 684*7697SMichael.Christensen@Sun.COM (loopcnt++ < ds_retries)) { 685*7697SMichael.Christensen@Sun.COM drv_usecwait(ds_delay); 686*7697SMichael.Christensen@Sun.COM } else { 687*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: send_msg: ldc_write " 688*7697SMichael.Christensen@Sun.COM "failed (%d), %d bytes remaining" DS_EOL, 689*7697SMichael.Christensen@Sun.COM PORTID(port), rv, (int)amt_left); 690*7697SMichael.Christensen@Sun.COM goto error; 691*7697SMichael.Christensen@Sun.COM } 692*7697SMichael.Christensen@Sun.COM } else { 693*7697SMichael.Christensen@Sun.COM amt_left -= msglen; 694*7697SMichael.Christensen@Sun.COM currp += msglen; 695*7697SMichael.Christensen@Sun.COM msglen = amt_left; 696*7697SMichael.Christensen@Sun.COM loopcnt = 0; 697*7697SMichael.Christensen@Sun.COM } 698*7697SMichael.Christensen@Sun.COM } while (amt_left > 0); 699*7697SMichael.Christensen@Sun.COM error: 700*7697SMichael.Christensen@Sun.COM mutex_exit(&port->tx_lock); 701*7697SMichael.Christensen@Sun.COM 702*7697SMichael.Christensen@Sun.COM return (rv); 703*7697SMichael.Christensen@Sun.COM } 704*7697SMichael.Christensen@Sun.COM 705*7697SMichael.Christensen@Sun.COM /* END LDC SUPPORT FUNCTIONS */ 706*7697SMichael.Christensen@Sun.COM 707*7697SMichael.Christensen@Sun.COM 708*7697SMichael.Christensen@Sun.COM /* BEGIN DS PROTOCOL SUPPORT FUNCTIONS */ 709*7697SMichael.Christensen@Sun.COM 710*7697SMichael.Christensen@Sun.COM static void 711*7697SMichael.Christensen@Sun.COM ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len) 712*7697SMichael.Christensen@Sun.COM { 713*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 714*7697SMichael.Christensen@Sun.COM ds_init_ack_t *ack; 715*7697SMichael.Christensen@Sun.COM ds_init_nack_t *nack; 716*7697SMichael.Christensen@Sun.COM char *msg; 717*7697SMichael.Christensen@Sun.COM size_t msglen; 718*7697SMichael.Christensen@Sun.COM ds_init_req_t *req; 719*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_req_t); 720*7697SMichael.Christensen@Sun.COM uint16_t new_major; 721*7697SMichael.Christensen@Sun.COM uint16_t new_minor; 722*7697SMichael.Christensen@Sun.COM boolean_t match; 723*7697SMichael.Christensen@Sun.COM 724*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 725*7697SMichael.Christensen@Sun.COM if (len != explen) { 726*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <init_req: invalid message " 727*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 728*7697SMichael.Christensen@Sun.COM explen); 729*7697SMichael.Christensen@Sun.COM return; 730*7697SMichael.Christensen@Sun.COM } 731*7697SMichael.Christensen@Sun.COM 732*7697SMichael.Christensen@Sun.COM req = (ds_init_req_t *)(buf + DS_HDR_SZ); 733*7697SMichael.Christensen@Sun.COM 734*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_req: ver=%d.%d" DS_EOL, 735*7697SMichael.Christensen@Sun.COM PORTID(port), req->major_vers, req->minor_vers); 736*7697SMichael.Christensen@Sun.COM 737*7697SMichael.Christensen@Sun.COM match = negotiate_version(DS_NUM_VER, &ds_vers[0], 738*7697SMichael.Christensen@Sun.COM req->major_vers, &new_major, &new_minor); 739*7697SMichael.Christensen@Sun.COM 740*7697SMichael.Christensen@Sun.COM /* 741*7697SMichael.Christensen@Sun.COM * Check version info. ACK only if the major numbers exactly 742*7697SMichael.Christensen@Sun.COM * match. The service entity can retry with a new minor 743*7697SMichael.Christensen@Sun.COM * based on the response sent as part of the NACK. 744*7697SMichael.Christensen@Sun.COM */ 745*7697SMichael.Christensen@Sun.COM if (match) { 746*7697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_init_ack_t); 747*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 748*7697SMichael.Christensen@Sun.COM 749*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 750*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_ACK; 751*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_ack_t); 752*7697SMichael.Christensen@Sun.COM 753*7697SMichael.Christensen@Sun.COM ack = (ds_init_ack_t *)(msg + DS_HDR_SZ); 754*7697SMichael.Christensen@Sun.COM ack->minor_vers = MIN(new_minor, req->minor_vers); 755*7697SMichael.Christensen@Sun.COM 756*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_ack>: minor=0x%04X" DS_EOL, 757*7697SMichael.Christensen@Sun.COM PORTID(port), MIN(new_minor, req->minor_vers)); 758*7697SMichael.Christensen@Sun.COM } else { 759*7697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_init_nack_t); 760*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 761*7697SMichael.Christensen@Sun.COM 762*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 763*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_NACK; 764*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_nack_t); 765*7697SMichael.Christensen@Sun.COM 766*7697SMichael.Christensen@Sun.COM nack = (ds_init_nack_t *)(msg + DS_HDR_SZ); 767*7697SMichael.Christensen@Sun.COM nack->major_vers = new_major; 768*7697SMichael.Christensen@Sun.COM 769*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_nack>: major=0x%04X" DS_EOL, 770*7697SMichael.Christensen@Sun.COM PORTID(port), new_major); 771*7697SMichael.Christensen@Sun.COM } 772*7697SMichael.Christensen@Sun.COM 773*7697SMichael.Christensen@Sun.COM /* 774*7697SMichael.Christensen@Sun.COM * Send the response 775*7697SMichael.Christensen@Sun.COM */ 776*7697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 777*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 778*7697SMichael.Christensen@Sun.COM } 779*7697SMichael.Christensen@Sun.COM 780*7697SMichael.Christensen@Sun.COM static void 781*7697SMichael.Christensen@Sun.COM ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len) 782*7697SMichael.Christensen@Sun.COM { 783*7697SMichael.Christensen@Sun.COM ds_init_ack_t *ack; 784*7697SMichael.Christensen@Sun.COM ds_ver_t *ver; 785*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_ack_t); 786*7697SMichael.Christensen@Sun.COM 787*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 788*7697SMichael.Christensen@Sun.COM if (len != explen) { 789*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <init_ack: invalid message " 790*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 791*7697SMichael.Christensen@Sun.COM explen); 792*7697SMichael.Christensen@Sun.COM return; 793*7697SMichael.Christensen@Sun.COM } 794*7697SMichael.Christensen@Sun.COM 795*7697SMichael.Christensen@Sun.COM ack = (ds_init_ack_t *)(buf + DS_HDR_SZ); 796*7697SMichael.Christensen@Sun.COM 797*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 798*7697SMichael.Christensen@Sun.COM 799*7697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_INIT_REQ) { 800*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: invalid state: %d" 801*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 802*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 803*7697SMichael.Christensen@Sun.COM return; 804*7697SMichael.Christensen@Sun.COM } 805*7697SMichael.Christensen@Sun.COM 806*7697SMichael.Christensen@Sun.COM ver = &(ds_vers[port->ver_idx]); 807*7697SMichael.Christensen@Sun.COM 808*7697SMichael.Christensen@Sun.COM /* agreed upon a major version */ 809*7697SMichael.Christensen@Sun.COM port->ver.major = ver->major; 810*7697SMichael.Christensen@Sun.COM 811*7697SMichael.Christensen@Sun.COM /* 812*7697SMichael.Christensen@Sun.COM * If the returned minor version is larger than 813*7697SMichael.Christensen@Sun.COM * the requested minor version, use the lower of 814*7697SMichael.Christensen@Sun.COM * the two, i.e. the requested version. 815*7697SMichael.Christensen@Sun.COM */ 816*7697SMichael.Christensen@Sun.COM if (ack->minor_vers >= ver->minor) { 817*7697SMichael.Christensen@Sun.COM /* 818*7697SMichael.Christensen@Sun.COM * Use the minor version specified in the 819*7697SMichael.Christensen@Sun.COM * original request. 820*7697SMichael.Christensen@Sun.COM */ 821*7697SMichael.Christensen@Sun.COM port->ver.minor = ver->minor; 822*7697SMichael.Christensen@Sun.COM } else { 823*7697SMichael.Christensen@Sun.COM /* 824*7697SMichael.Christensen@Sun.COM * Use the lower minor version returned in 825*7697SMichael.Christensen@Sun.COM * the ack. By definition, all lower minor 826*7697SMichael.Christensen@Sun.COM * versions must be supported. 827*7697SMichael.Christensen@Sun.COM */ 828*7697SMichael.Christensen@Sun.COM port->ver.minor = ack->minor_vers; 829*7697SMichael.Christensen@Sun.COM } 830*7697SMichael.Christensen@Sun.COM 831*7697SMichael.Christensen@Sun.COM port->state = DS_PORT_READY; 832*7697SMichael.Christensen@Sun.COM 833*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready v%d.%d" DS_EOL, 834*7697SMichael.Christensen@Sun.COM PORTID(port), port->ver.major, port->ver.minor); 835*7697SMichael.Christensen@Sun.COM 836*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 837*7697SMichael.Christensen@Sun.COM 838*7697SMichael.Christensen@Sun.COM /* 839*7697SMichael.Christensen@Sun.COM * The port came up, so update all the services 840*7697SMichael.Christensen@Sun.COM * with this information. Follow that up with an 841*7697SMichael.Christensen@Sun.COM * attempt to register any service that is not 842*7697SMichael.Christensen@Sun.COM * already registered. 843*7697SMichael.Christensen@Sun.COM */ 844*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 845*7697SMichael.Christensen@Sun.COM 846*7697SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_port_up, port); 847*7697SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_register, NULL); 848*7697SMichael.Christensen@Sun.COM 849*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 850*7697SMichael.Christensen@Sun.COM } 851*7697SMichael.Christensen@Sun.COM 852*7697SMichael.Christensen@Sun.COM static void 853*7697SMichael.Christensen@Sun.COM ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len) 854*7697SMichael.Christensen@Sun.COM { 855*7697SMichael.Christensen@Sun.COM int idx; 856*7697SMichael.Christensen@Sun.COM ds_init_nack_t *nack; 857*7697SMichael.Christensen@Sun.COM ds_ver_t *ver; 858*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_nack_t); 859*7697SMichael.Christensen@Sun.COM 860*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 861*7697SMichael.Christensen@Sun.COM if (len != explen) { 862*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: invalid message " 863*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 864*7697SMichael.Christensen@Sun.COM explen); 865*7697SMichael.Christensen@Sun.COM return; 866*7697SMichael.Christensen@Sun.COM } 867*7697SMichael.Christensen@Sun.COM 868*7697SMichael.Christensen@Sun.COM nack = (ds_init_nack_t *)(buf + DS_HDR_SZ); 869*7697SMichael.Christensen@Sun.COM 870*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 871*7697SMichael.Christensen@Sun.COM 872*7697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_INIT_REQ) { 873*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: invalid state: %d" 874*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 875*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 876*7697SMichael.Christensen@Sun.COM return; 877*7697SMichael.Christensen@Sun.COM } 878*7697SMichael.Christensen@Sun.COM 879*7697SMichael.Christensen@Sun.COM ver = &(ds_vers[port->ver_idx]); 880*7697SMichael.Christensen@Sun.COM 881*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: req=v%d.%d, nack=v%d.x" 882*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), ver->major, ver->minor, nack->major_vers); 883*7697SMichael.Christensen@Sun.COM 884*7697SMichael.Christensen@Sun.COM if (nack->major_vers == 0) { 885*7697SMichael.Christensen@Sun.COM /* no supported protocol version */ 886*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS not supported" 887*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 888*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 889*7697SMichael.Christensen@Sun.COM return; 890*7697SMichael.Christensen@Sun.COM } 891*7697SMichael.Christensen@Sun.COM 892*7697SMichael.Christensen@Sun.COM /* 893*7697SMichael.Christensen@Sun.COM * Walk the version list, looking for a major version 894*7697SMichael.Christensen@Sun.COM * that is as close to the requested major version as 895*7697SMichael.Christensen@Sun.COM * possible. 896*7697SMichael.Christensen@Sun.COM */ 897*7697SMichael.Christensen@Sun.COM for (idx = port->ver_idx; idx < DS_NUM_VER; idx++) { 898*7697SMichael.Christensen@Sun.COM if (ds_vers[idx].major <= nack->major_vers) { 899*7697SMichael.Christensen@Sun.COM /* found a version to try */ 900*7697SMichael.Christensen@Sun.COM goto done; 901*7697SMichael.Christensen@Sun.COM } 902*7697SMichael.Christensen@Sun.COM } 903*7697SMichael.Christensen@Sun.COM 904*7697SMichael.Christensen@Sun.COM if (idx == DS_NUM_VER) { 905*7697SMichael.Christensen@Sun.COM /* no supported version */ 906*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS v%d.x not " 907*7697SMichael.Christensen@Sun.COM "supported" DS_EOL, PORTID(port), nack->major_vers); 908*7697SMichael.Christensen@Sun.COM 909*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 910*7697SMichael.Christensen@Sun.COM return; 911*7697SMichael.Christensen@Sun.COM } 912*7697SMichael.Christensen@Sun.COM 913*7697SMichael.Christensen@Sun.COM done: 914*7697SMichael.Christensen@Sun.COM /* start the handshake again */ 915*7697SMichael.Christensen@Sun.COM port->ver_idx = idx; 916*7697SMichael.Christensen@Sun.COM port->state = DS_PORT_LDC_INIT; 917*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 918*7697SMichael.Christensen@Sun.COM 919*7697SMichael.Christensen@Sun.COM ds_send_init_req(port); 920*7697SMichael.Christensen@Sun.COM 921*7697SMichael.Christensen@Sun.COM } 922*7697SMichael.Christensen@Sun.COM 923*7697SMichael.Christensen@Sun.COM static ds_svc_t * 924*7697SMichael.Christensen@Sun.COM ds_find_svc_by_id_port(char *svc_id, int is_client, ds_port_t *port) 925*7697SMichael.Christensen@Sun.COM { 926*7697SMichael.Christensen@Sun.COM int idx; 927*7697SMichael.Christensen@Sun.COM ds_svc_t *svc, *found_svc = 0; 928*7697SMichael.Christensen@Sun.COM uint32_t flag_match = is_client ? DSSF_ISCLIENT : 0; 929*7697SMichael.Christensen@Sun.COM 930*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 931*7697SMichael.Christensen@Sun.COM 932*7697SMichael.Christensen@Sun.COM /* walk every table entry */ 933*7697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 934*7697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 935*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 936*7697SMichael.Christensen@Sun.COM continue; 937*7697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, svc_id) != 0) 938*7697SMichael.Christensen@Sun.COM continue; 939*7697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != flag_match) 940*7697SMichael.Christensen@Sun.COM continue; 941*7697SMichael.Christensen@Sun.COM if (port != NULL && svc->port == port) { 942*7697SMichael.Christensen@Sun.COM return (svc); 943*7697SMichael.Christensen@Sun.COM } else if (svc->state == DS_SVC_INACTIVE) { 944*7697SMichael.Christensen@Sun.COM found_svc = svc; 945*7697SMichael.Christensen@Sun.COM } else if (!found_svc) { 946*7697SMichael.Christensen@Sun.COM found_svc = svc; 947*7697SMichael.Christensen@Sun.COM } 948*7697SMichael.Christensen@Sun.COM } 949*7697SMichael.Christensen@Sun.COM 950*7697SMichael.Christensen@Sun.COM return (found_svc); 951*7697SMichael.Christensen@Sun.COM } 952*7697SMichael.Christensen@Sun.COM 953*7697SMichael.Christensen@Sun.COM static void 954*7697SMichael.Christensen@Sun.COM ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len) 955*7697SMichael.Christensen@Sun.COM { 956*7697SMichael.Christensen@Sun.COM ds_reg_req_t *req; 957*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 958*7697SMichael.Christensen@Sun.COM ds_reg_ack_t *ack; 959*7697SMichael.Christensen@Sun.COM ds_reg_nack_t *nack; 960*7697SMichael.Christensen@Sun.COM char *msg; 961*7697SMichael.Christensen@Sun.COM size_t msglen; 962*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_req_t); 963*7697SMichael.Christensen@Sun.COM ds_svc_t *svc = NULL; 964*7697SMichael.Christensen@Sun.COM ds_ver_t version; 965*7697SMichael.Christensen@Sun.COM uint16_t new_major; 966*7697SMichael.Christensen@Sun.COM uint16_t new_minor; 967*7697SMichael.Christensen@Sun.COM boolean_t match; 968*7697SMichael.Christensen@Sun.COM 969*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 970*7697SMichael.Christensen@Sun.COM if (len < explen) { 971*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_req: invalid message " 972*7697SMichael.Christensen@Sun.COM "length (%ld), expected at least %ld" DS_EOL, 973*7697SMichael.Christensen@Sun.COM PORTID(port), len, explen); 974*7697SMichael.Christensen@Sun.COM return; 975*7697SMichael.Christensen@Sun.COM } 976*7697SMichael.Christensen@Sun.COM 977*7697SMichael.Christensen@Sun.COM req = (ds_reg_req_t *)(buf + DS_HDR_SZ); 978*7697SMichael.Christensen@Sun.COM 979*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' ver=%d.%d, hdl=0x%llx" 980*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), req->svc_id, req->major_vers, req->minor_vers, 981*7697SMichael.Christensen@Sun.COM (u_longlong_t)req->svc_handle); 982*7697SMichael.Christensen@Sun.COM 983*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 984*7697SMichael.Christensen@Sun.COM svc = ds_find_svc_by_id_port(req->svc_id, 985*7697SMichael.Christensen@Sun.COM DS_HDL_ISCLIENT(req->svc_handle) == 0, port); 986*7697SMichael.Christensen@Sun.COM if (svc == NULL) { 987*7697SMichael.Christensen@Sun.COM 988*7697SMichael.Christensen@Sun.COM do_reg_nack: 989*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 990*7697SMichael.Christensen@Sun.COM 991*7697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_nack_t); 992*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 993*7697SMichael.Christensen@Sun.COM 994*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 995*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_NACK; 996*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_nack_t); 997*7697SMichael.Christensen@Sun.COM 998*7697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ); 999*7697SMichael.Christensen@Sun.COM nack->svc_handle = req->svc_handle; 1000*7697SMichael.Christensen@Sun.COM nack->result = DS_REG_VER_NACK; 1001*7697SMichael.Christensen@Sun.COM nack->major_vers = 0; 1002*7697SMichael.Christensen@Sun.COM 1003*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s'" DS_EOL, 1004*7697SMichael.Christensen@Sun.COM PORTID(port), req->svc_id); 1005*7697SMichael.Christensen@Sun.COM /* 1006*7697SMichael.Christensen@Sun.COM * Send the response 1007*7697SMichael.Christensen@Sun.COM */ 1008*7697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 1009*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 1010*7697SMichael.Christensen@Sun.COM return; 1011*7697SMichael.Christensen@Sun.COM } 1012*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' found, hdl: 0x%llx" DS_EOL, 1013*7697SMichael.Christensen@Sun.COM PORTID(port), req->svc_id, (u_longlong_t)svc->hdl); 1014*7697SMichael.Christensen@Sun.COM 1015*7697SMichael.Christensen@Sun.COM /* 1016*7697SMichael.Christensen@Sun.COM * A client sends out a reg req in order to force service providers to 1017*7697SMichael.Christensen@Sun.COM * initiate a reg req from their end (limitation in the protocol). If a 1018*7697SMichael.Christensen@Sun.COM * service provider already thinks it's talking to someone on that port, 1019*7697SMichael.Christensen@Sun.COM * something's gone wrong (probably an unreg req request was dropped). 1020*7697SMichael.Christensen@Sun.COM * If we see that the service is in the wrong state, reset it. 1021*7697SMichael.Christensen@Sun.COM */ 1022*7697SMichael.Christensen@Sun.COM 1023*7697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(req->svc_handle)) { 1024*7697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_INACTIVE) { 1025*7697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, port); 1026*7697SMichael.Christensen@Sun.COM } 1027*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging client" 1028*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), req->svc_id); 1029*7697SMichael.Christensen@Sun.COM (void) ds_svc_port_up(svc, port); 1030*7697SMichael.Christensen@Sun.COM (void) ds_svc_register_onport(svc, port); 1031*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1032*7697SMichael.Christensen@Sun.COM return; 1033*7697SMichael.Christensen@Sun.COM } 1034*7697SMichael.Christensen@Sun.COM 1035*7697SMichael.Christensen@Sun.COM /* 1036*7697SMichael.Christensen@Sun.COM * Only remote service providers can initiate a registration. The 1037*7697SMichael.Christensen@Sun.COM * local sevice from here must be a client service. 1038*7697SMichael.Christensen@Sun.COM */ 1039*7697SMichael.Christensen@Sun.COM 1040*7697SMichael.Christensen@Sun.COM match = negotiate_version(svc->cap.nvers, svc->cap.vers, 1041*7697SMichael.Christensen@Sun.COM req->major_vers, &new_major, &new_minor); 1042*7697SMichael.Christensen@Sun.COM 1043*7697SMichael.Christensen@Sun.COM /* 1044*7697SMichael.Christensen@Sun.COM * Check version info. ACK only if the major numbers exactly 1045*7697SMichael.Christensen@Sun.COM * match. The service entity can retry with a new minor 1046*7697SMichael.Christensen@Sun.COM * based on the response sent as part of the NACK. 1047*7697SMichael.Christensen@Sun.COM */ 1048*7697SMichael.Christensen@Sun.COM if (match) { 1049*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' svc%d: state: %x " 1050*7697SMichael.Christensen@Sun.COM "svc_portid: %d" DS_EOL, PORTID(port), req->svc_id, 1051*7697SMichael.Christensen@Sun.COM (int)DS_HDL2IDX(svc->hdl), svc->state, 1052*7697SMichael.Christensen@Sun.COM (int)(svc->port == NULL ? -1 : PORTID(svc->port))); 1053*7697SMichael.Christensen@Sun.COM /* 1054*7697SMichael.Christensen@Sun.COM * If the current local service is already in use and 1055*7697SMichael.Christensen@Sun.COM * it's not on this port, clone it. 1056*7697SMichael.Christensen@Sun.COM */ 1057*7697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_INACTIVE) { 1058*7697SMichael.Christensen@Sun.COM if (svc->port != NULL && port == svc->port) { 1059*7697SMichael.Christensen@Sun.COM /* 1060*7697SMichael.Christensen@Sun.COM * Someone probably dropped an unreg req 1061*7697SMichael.Christensen@Sun.COM * somewhere. Force a local unreg. 1062*7697SMichael.Christensen@Sun.COM */ 1063*7697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, port); 1064*7697SMichael.Christensen@Sun.COM } else if (!DS_HDL_ISCLIENT(svc->hdl)) { 1065*7697SMichael.Christensen@Sun.COM /* 1066*7697SMichael.Christensen@Sun.COM * Can't clone a non-client (service provider) 1067*7697SMichael.Christensen@Sun.COM * handle. This is because old in-kernel 1068*7697SMichael.Christensen@Sun.COM * service providers can't deal with multiple 1069*7697SMichael.Christensen@Sun.COM * handles. 1070*7697SMichael.Christensen@Sun.COM */ 1071*7697SMichael.Christensen@Sun.COM goto do_reg_nack; 1072*7697SMichael.Christensen@Sun.COM } else { 1073*7697SMichael.Christensen@Sun.COM svc = ds_svc_clone(svc); 1074*7697SMichael.Christensen@Sun.COM } 1075*7697SMichael.Christensen@Sun.COM } 1076*7697SMichael.Christensen@Sun.COM svc->port = port; 1077*7697SMichael.Christensen@Sun.COM svc->svc_hdl = req->svc_handle; 1078*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 1079*7697SMichael.Christensen@Sun.COM 1080*7697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_ack_t); 1081*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 1082*7697SMichael.Christensen@Sun.COM 1083*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 1084*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_ACK; 1085*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_ack_t); 1086*7697SMichael.Christensen@Sun.COM 1087*7697SMichael.Christensen@Sun.COM ack = (ds_reg_ack_t *)(msg + DS_HDR_SZ); 1088*7697SMichael.Christensen@Sun.COM ack->svc_handle = req->svc_handle; 1089*7697SMichael.Christensen@Sun.COM ack->minor_vers = MIN(new_minor, req->minor_vers); 1090*7697SMichael.Christensen@Sun.COM 1091*7697SMichael.Christensen@Sun.COM 1092*7697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 1093*7697SMichael.Christensen@Sun.COM /* Call the registration callback */ 1094*7697SMichael.Christensen@Sun.COM version.major = req->major_vers; 1095*7697SMichael.Christensen@Sun.COM version.minor = ack->minor_vers; 1096*7697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &version, 1097*7697SMichael.Christensen@Sun.COM svc->hdl); 1098*7697SMichael.Christensen@Sun.COM } 1099*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1100*7697SMichael.Christensen@Sun.COM 1101*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_ack>: '%s' minor=0x%04X" 1102*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, 1103*7697SMichael.Christensen@Sun.COM MIN(new_minor, req->minor_vers)); 1104*7697SMichael.Christensen@Sun.COM } else { 1105*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1106*7697SMichael.Christensen@Sun.COM 1107*7697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_nack_t); 1108*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 1109*7697SMichael.Christensen@Sun.COM 1110*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 1111*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_NACK; 1112*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_nack_t); 1113*7697SMichael.Christensen@Sun.COM 1114*7697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ); 1115*7697SMichael.Christensen@Sun.COM nack->svc_handle = req->svc_handle; 1116*7697SMichael.Christensen@Sun.COM nack->result = DS_REG_VER_NACK; 1117*7697SMichael.Christensen@Sun.COM nack->major_vers = new_major; 1118*7697SMichael.Christensen@Sun.COM 1119*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s' major=0x%04X" 1120*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, new_major); 1121*7697SMichael.Christensen@Sun.COM } 1122*7697SMichael.Christensen@Sun.COM 1123*7697SMichael.Christensen@Sun.COM /* send message */ 1124*7697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 1125*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 1126*7697SMichael.Christensen@Sun.COM } 1127*7697SMichael.Christensen@Sun.COM 1128*7697SMichael.Christensen@Sun.COM static void 1129*7697SMichael.Christensen@Sun.COM ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len) 1130*7697SMichael.Christensen@Sun.COM { 1131*7697SMichael.Christensen@Sun.COM ds_reg_ack_t *ack; 1132*7697SMichael.Christensen@Sun.COM ds_ver_t *ver; 1133*7697SMichael.Christensen@Sun.COM ds_ver_t tmpver; 1134*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 1135*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_ack_t); 1136*7697SMichael.Christensen@Sun.COM 1137*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 1138*7697SMichael.Christensen@Sun.COM if (len != explen) { 1139*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid message " 1140*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 1141*7697SMichael.Christensen@Sun.COM explen); 1142*7697SMichael.Christensen@Sun.COM return; 1143*7697SMichael.Christensen@Sun.COM } 1144*7697SMichael.Christensen@Sun.COM 1145*7697SMichael.Christensen@Sun.COM ack = (ds_reg_ack_t *)(buf + DS_HDR_SZ); 1146*7697SMichael.Christensen@Sun.COM 1147*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 1148*7697SMichael.Christensen@Sun.COM 1149*7697SMichael.Christensen@Sun.COM /* 1150*7697SMichael.Christensen@Sun.COM * This searches for service based on how we generate handles 1151*7697SMichael.Christensen@Sun.COM * and so only works because this is a reg ack. 1152*7697SMichael.Christensen@Sun.COM */ 1153*7697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(ack->svc_handle) || 1154*7697SMichael.Christensen@Sun.COM (svc = ds_get_svc(ack->svc_handle)) == NULL) { 1155*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid handle 0x%llx" 1156*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle); 1157*7697SMichael.Christensen@Sun.COM goto done; 1158*7697SMichael.Christensen@Sun.COM } 1159*7697SMichael.Christensen@Sun.COM 1160*7697SMichael.Christensen@Sun.COM /* make sure the message makes sense */ 1161*7697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_REG_PENDING) { 1162*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid state (%d)" DS_EOL, 1163*7697SMichael.Christensen@Sun.COM PORTID(port), svc->state); 1164*7697SMichael.Christensen@Sun.COM goto done; 1165*7697SMichael.Christensen@Sun.COM } 1166*7697SMichael.Christensen@Sun.COM 1167*7697SMichael.Christensen@Sun.COM ver = &(svc->cap.vers[svc->ver_idx]); 1168*7697SMichael.Christensen@Sun.COM 1169*7697SMichael.Christensen@Sun.COM /* major version has been agreed upon */ 1170*7697SMichael.Christensen@Sun.COM svc->ver.major = ver->major; 1171*7697SMichael.Christensen@Sun.COM 1172*7697SMichael.Christensen@Sun.COM if (ack->minor_vers >= ver->minor) { 1173*7697SMichael.Christensen@Sun.COM /* 1174*7697SMichael.Christensen@Sun.COM * Use the minor version specified in the 1175*7697SMichael.Christensen@Sun.COM * original request. 1176*7697SMichael.Christensen@Sun.COM */ 1177*7697SMichael.Christensen@Sun.COM svc->ver.minor = ver->minor; 1178*7697SMichael.Christensen@Sun.COM } else { 1179*7697SMichael.Christensen@Sun.COM /* 1180*7697SMichael.Christensen@Sun.COM * Use the lower minor version returned in 1181*7697SMichael.Christensen@Sun.COM * the ack. By defninition, all lower minor 1182*7697SMichael.Christensen@Sun.COM * versions must be supported. 1183*7697SMichael.Christensen@Sun.COM */ 1184*7697SMichael.Christensen@Sun.COM svc->ver.minor = ack->minor_vers; 1185*7697SMichael.Christensen@Sun.COM } 1186*7697SMichael.Christensen@Sun.COM 1187*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 1188*7697SMichael.Christensen@Sun.COM svc->port = port; 1189*7697SMichael.Christensen@Sun.COM 1190*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_ack: '%s' v%d.%d ready, hdl=0x%llx" 1191*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, svc->ver.major, 1192*7697SMichael.Christensen@Sun.COM svc->ver.minor, (u_longlong_t)svc->hdl); 1193*7697SMichael.Christensen@Sun.COM 1194*7697SMichael.Christensen@Sun.COM /* notify the client that registration is complete */ 1195*7697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 1196*7697SMichael.Christensen@Sun.COM /* 1197*7697SMichael.Christensen@Sun.COM * Use a temporary version structure so that 1198*7697SMichael.Christensen@Sun.COM * the copy in the svc structure cannot be 1199*7697SMichael.Christensen@Sun.COM * modified by the client. 1200*7697SMichael.Christensen@Sun.COM */ 1201*7697SMichael.Christensen@Sun.COM tmpver.major = svc->ver.major; 1202*7697SMichael.Christensen@Sun.COM tmpver.minor = svc->ver.minor; 1203*7697SMichael.Christensen@Sun.COM 1204*7697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &tmpver, svc->hdl); 1205*7697SMichael.Christensen@Sun.COM } 1206*7697SMichael.Christensen@Sun.COM 1207*7697SMichael.Christensen@Sun.COM done: 1208*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1209*7697SMichael.Christensen@Sun.COM } 1210*7697SMichael.Christensen@Sun.COM 1211*7697SMichael.Christensen@Sun.COM static void 1212*7697SMichael.Christensen@Sun.COM ds_try_next_port(ds_svc_t *svc, int portid) 1213*7697SMichael.Christensen@Sun.COM { 1214*7697SMichael.Christensen@Sun.COM ds_port_t *port; 1215*7697SMichael.Christensen@Sun.COM ds_portset_t totry; 1216*7697SMichael.Christensen@Sun.COM int i; 1217*7697SMichael.Christensen@Sun.COM 1218*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x %s" DS_EOL, portid, __func__); 1219*7697SMichael.Christensen@Sun.COM DS_PORTSET_NOT(totry, svc->tried); 1220*7697SMichael.Christensen@Sun.COM DS_PORTSET_AND(totry, svc->avail); 1221*7697SMichael.Christensen@Sun.COM if (DS_PORTSET_ISNULL(totry)) 1222*7697SMichael.Christensen@Sun.COM return; 1223*7697SMichael.Christensen@Sun.COM 1224*7697SMichael.Christensen@Sun.COM for (i = 0; i < DS_MAX_PORTS; i++, portid++) { 1225*7697SMichael.Christensen@Sun.COM if (portid >= DS_MAX_PORTS) { 1226*7697SMichael.Christensen@Sun.COM portid = 0; 1227*7697SMichael.Christensen@Sun.COM } 1228*7697SMichael.Christensen@Sun.COM 1229*7697SMichael.Christensen@Sun.COM /* 1230*7697SMichael.Christensen@Sun.COM * If the port is not in the available list, 1231*7697SMichael.Christensen@Sun.COM * it is not a candidate for registration. 1232*7697SMichael.Christensen@Sun.COM */ 1233*7697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(totry, portid)) { 1234*7697SMichael.Christensen@Sun.COM continue; 1235*7697SMichael.Christensen@Sun.COM } 1236*7697SMichael.Christensen@Sun.COM 1237*7697SMichael.Christensen@Sun.COM port = &ds_ports[portid]; 1238*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s trying ldc.id: %d" DS_EOL, 1239*7697SMichael.Christensen@Sun.COM portid, __func__, (uint_t)(port->ldc.id)); 1240*7697SMichael.Christensen@Sun.COM if (ds_send_reg_req(svc, port) == 0) { 1241*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send OK" DS_EOL, 1242*7697SMichael.Christensen@Sun.COM portid, __func__); 1243*7697SMichael.Christensen@Sun.COM /* register sent successfully */ 1244*7697SMichael.Christensen@Sun.COM break; 1245*7697SMichael.Christensen@Sun.COM } 1246*7697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send FAIL" DS_EOL, 1247*7697SMichael.Christensen@Sun.COM portid, __func__); 1248*7697SMichael.Christensen@Sun.COM 1249*7697SMichael.Christensen@Sun.COM /* reset the service to try the next port */ 1250*7697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 1251*7697SMichael.Christensen@Sun.COM } 1252*7697SMichael.Christensen@Sun.COM } 1253*7697SMichael.Christensen@Sun.COM 1254*7697SMichael.Christensen@Sun.COM static void 1255*7697SMichael.Christensen@Sun.COM ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len) 1256*7697SMichael.Christensen@Sun.COM { 1257*7697SMichael.Christensen@Sun.COM ds_reg_nack_t *nack; 1258*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 1259*7697SMichael.Christensen@Sun.COM int idx; 1260*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_nack_t); 1261*7697SMichael.Christensen@Sun.COM 1262*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 1263*7697SMichael.Christensen@Sun.COM if (len != explen) { 1264*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid message " 1265*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 1266*7697SMichael.Christensen@Sun.COM explen); 1267*7697SMichael.Christensen@Sun.COM return; 1268*7697SMichael.Christensen@Sun.COM } 1269*7697SMichael.Christensen@Sun.COM 1270*7697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(buf + DS_HDR_SZ); 1271*7697SMichael.Christensen@Sun.COM 1272*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 1273*7697SMichael.Christensen@Sun.COM 1274*7697SMichael.Christensen@Sun.COM /* 1275*7697SMichael.Christensen@Sun.COM * We expect a reg_nack for a client ping. 1276*7697SMichael.Christensen@Sun.COM */ 1277*7697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(nack->svc_handle)) { 1278*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: ping hdl: 0x%llx" 1279*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 1280*7697SMichael.Christensen@Sun.COM goto done; 1281*7697SMichael.Christensen@Sun.COM } 1282*7697SMichael.Christensen@Sun.COM 1283*7697SMichael.Christensen@Sun.COM /* 1284*7697SMichael.Christensen@Sun.COM * This searches for service based on how we generate handles 1285*7697SMichael.Christensen@Sun.COM * and so only works because this is a reg nack. 1286*7697SMichael.Christensen@Sun.COM */ 1287*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(nack->svc_handle)) == NULL) { 1288*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid handle 0x%llx" 1289*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 1290*7697SMichael.Christensen@Sun.COM goto done; 1291*7697SMichael.Christensen@Sun.COM } 1292*7697SMichael.Christensen@Sun.COM 1293*7697SMichael.Christensen@Sun.COM /* make sure the message makes sense */ 1294*7697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_REG_PENDING) { 1295*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid state (%d)" DS_EOL, 1296*7697SMichael.Christensen@Sun.COM PORTID(port), svc->state); 1297*7697SMichael.Christensen@Sun.COM goto done; 1298*7697SMichael.Christensen@Sun.COM } 1299*7697SMichael.Christensen@Sun.COM 1300*7697SMichael.Christensen@Sun.COM if (nack->result == DS_REG_DUP) { 1301*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: duplicate registration " 1302*7697SMichael.Christensen@Sun.COM " for %s" DS_EOL, PORTID(port), svc->cap.svc_id); 1303*7697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 1304*7697SMichael.Christensen@Sun.COM goto done; 1305*7697SMichael.Christensen@Sun.COM } 1306*7697SMichael.Christensen@Sun.COM 1307*7697SMichael.Christensen@Sun.COM /* 1308*7697SMichael.Christensen@Sun.COM * A major version of zero indicates that the 1309*7697SMichael.Christensen@Sun.COM * service is not supported at all. 1310*7697SMichael.Christensen@Sun.COM */ 1311*7697SMichael.Christensen@Sun.COM if (nack->major_vers == 0) { 1312*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' not supported" 1313*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id); 1314*7697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 1315*7697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 1316*7697SMichael.Christensen@Sun.COM ds_try_next_port(svc, PORTID(port) + 1); 1317*7697SMichael.Christensen@Sun.COM goto done; 1318*7697SMichael.Christensen@Sun.COM } 1319*7697SMichael.Christensen@Sun.COM 1320*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' hdl=0x%llx, nack=%d.x" 1321*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, 1322*7697SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle, nack->major_vers); 1323*7697SMichael.Christensen@Sun.COM 1324*7697SMichael.Christensen@Sun.COM /* 1325*7697SMichael.Christensen@Sun.COM * Walk the version list for the service, looking for 1326*7697SMichael.Christensen@Sun.COM * a major version that is as close to the requested 1327*7697SMichael.Christensen@Sun.COM * major version as possible. 1328*7697SMichael.Christensen@Sun.COM */ 1329*7697SMichael.Christensen@Sun.COM for (idx = svc->ver_idx; idx < svc->cap.nvers; idx++) { 1330*7697SMichael.Christensen@Sun.COM if (svc->cap.vers[idx].major <= nack->major_vers) { 1331*7697SMichael.Christensen@Sun.COM /* found a version to try */ 1332*7697SMichael.Christensen@Sun.COM break; 1333*7697SMichael.Christensen@Sun.COM } 1334*7697SMichael.Christensen@Sun.COM } 1335*7697SMichael.Christensen@Sun.COM 1336*7697SMichael.Christensen@Sun.COM if (idx == svc->cap.nvers) { 1337*7697SMichael.Christensen@Sun.COM /* no supported version */ 1338*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: %s v%d.x not supported" 1339*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, nack->major_vers); 1340*7697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 1341*7697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 1342*7697SMichael.Christensen@Sun.COM ds_try_next_port(svc, PORTID(port) + 1); 1343*7697SMichael.Christensen@Sun.COM goto done; 1344*7697SMichael.Christensen@Sun.COM } 1345*7697SMichael.Christensen@Sun.COM 1346*7697SMichael.Christensen@Sun.COM /* start the handshake again */ 1347*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 1348*7697SMichael.Christensen@Sun.COM svc->ver_idx = idx; 1349*7697SMichael.Christensen@Sun.COM 1350*7697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 1351*7697SMichael.Christensen@Sun.COM 1352*7697SMichael.Christensen@Sun.COM done: 1353*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1354*7697SMichael.Christensen@Sun.COM } 1355*7697SMichael.Christensen@Sun.COM 1356*7697SMichael.Christensen@Sun.COM static void 1357*7697SMichael.Christensen@Sun.COM ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len) 1358*7697SMichael.Christensen@Sun.COM { 1359*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 1360*7697SMichael.Christensen@Sun.COM ds_unreg_req_t *req; 1361*7697SMichael.Christensen@Sun.COM ds_unreg_ack_t *ack; 1362*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 1363*7697SMichael.Christensen@Sun.COM char *msg; 1364*7697SMichael.Christensen@Sun.COM size_t msglen; 1365*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_req_t); 1366*7697SMichael.Christensen@Sun.COM 1367*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 1368*7697SMichael.Christensen@Sun.COM if (len != explen) { 1369*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_req: invalid message " 1370*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 1371*7697SMichael.Christensen@Sun.COM explen); 1372*7697SMichael.Christensen@Sun.COM return; 1373*7697SMichael.Christensen@Sun.COM } 1374*7697SMichael.Christensen@Sun.COM 1375*7697SMichael.Christensen@Sun.COM req = (ds_unreg_req_t *)(buf + DS_HDR_SZ); 1376*7697SMichael.Christensen@Sun.COM 1377*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 1378*7697SMichael.Christensen@Sun.COM 1379*7697SMichael.Christensen@Sun.COM /* lookup appropriate client or service */ 1380*7697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(req->svc_handle) || 1381*7697SMichael.Christensen@Sun.COM ((svc = ds_find_clnt_svc_by_hdl_port(req->svc_handle, port)) 1382*7697SMichael.Christensen@Sun.COM == NULL && ((svc = ds_get_svc(req->svc_handle)) == NULL || 1383*7697SMichael.Christensen@Sun.COM svc->port != port))) { 1384*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_req: invalid handle 0x%llx" 1385*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)req->svc_handle); 1386*7697SMichael.Christensen@Sun.COM ds_send_unreg_nack(port, req->svc_handle); 1387*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1388*7697SMichael.Christensen@Sun.COM return; 1389*7697SMichael.Christensen@Sun.COM } 1390*7697SMichael.Christensen@Sun.COM 1391*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: '%s' handle 0x%llx" DS_EOL, 1392*7697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle); 1393*7697SMichael.Christensen@Sun.COM 1394*7697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 1395*7697SMichael.Christensen@Sun.COM 1396*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_ack>: '%s' hdl=0x%llx" DS_EOL, 1397*7697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle); 1398*7697SMichael.Christensen@Sun.COM 1399*7697SMichael.Christensen@Sun.COM ds_check_for_dup_services(svc); 1400*7697SMichael.Christensen@Sun.COM 1401*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1402*7697SMichael.Christensen@Sun.COM 1403*7697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_ack_t); 1404*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 1405*7697SMichael.Christensen@Sun.COM 1406*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 1407*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG_ACK; 1408*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_ack_t); 1409*7697SMichael.Christensen@Sun.COM 1410*7697SMichael.Christensen@Sun.COM ack = (ds_unreg_ack_t *)(msg + DS_HDR_SZ); 1411*7697SMichael.Christensen@Sun.COM ack->svc_handle = req->svc_handle; 1412*7697SMichael.Christensen@Sun.COM 1413*7697SMichael.Christensen@Sun.COM /* send message */ 1414*7697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 1415*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 1416*7697SMichael.Christensen@Sun.COM 1417*7697SMichael.Christensen@Sun.COM } 1418*7697SMichael.Christensen@Sun.COM 1419*7697SMichael.Christensen@Sun.COM static void 1420*7697SMichael.Christensen@Sun.COM ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len) 1421*7697SMichael.Christensen@Sun.COM { 1422*7697SMichael.Christensen@Sun.COM ds_unreg_ack_t *ack; 1423*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_ack_t); 1424*7697SMichael.Christensen@Sun.COM 1425*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 1426*7697SMichael.Christensen@Sun.COM if (len != explen) { 1427*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_ack: invalid message " 1428*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 1429*7697SMichael.Christensen@Sun.COM explen); 1430*7697SMichael.Christensen@Sun.COM return; 1431*7697SMichael.Christensen@Sun.COM } 1432*7697SMichael.Christensen@Sun.COM 1433*7697SMichael.Christensen@Sun.COM ack = (ds_unreg_ack_t *)(buf + DS_HDR_SZ); 1434*7697SMichael.Christensen@Sun.COM 1435*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_ack: hdl=0x%llx" DS_EOL, 1436*7697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)ack->svc_handle); 1437*7697SMichael.Christensen@Sun.COM 1438*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 1439*7697SMichael.Christensen@Sun.COM 1440*7697SMichael.Christensen@Sun.COM /* 1441*7697SMichael.Christensen@Sun.COM * Since the unregister request was initiated locally, 1442*7697SMichael.Christensen@Sun.COM * the service structure has already been torn down. 1443*7697SMichael.Christensen@Sun.COM * Just perform a sanity check to make sure the message 1444*7697SMichael.Christensen@Sun.COM * is appropriate. 1445*7697SMichael.Christensen@Sun.COM */ 1446*7697SMichael.Christensen@Sun.COM if (ds_get_svc(ack->svc_handle) != NULL) { 1447*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_ack: handle 0x%llx in use" 1448*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle); 1449*7697SMichael.Christensen@Sun.COM } 1450*7697SMichael.Christensen@Sun.COM 1451*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1452*7697SMichael.Christensen@Sun.COM } 1453*7697SMichael.Christensen@Sun.COM 1454*7697SMichael.Christensen@Sun.COM static void 1455*7697SMichael.Christensen@Sun.COM ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len) 1456*7697SMichael.Christensen@Sun.COM { 1457*7697SMichael.Christensen@Sun.COM ds_unreg_nack_t *nack; 1458*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_nack_t); 1459*7697SMichael.Christensen@Sun.COM 1460*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 1461*7697SMichael.Christensen@Sun.COM if (len != explen) { 1462*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_nack: invalid message " 1463*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 1464*7697SMichael.Christensen@Sun.COM explen); 1465*7697SMichael.Christensen@Sun.COM return; 1466*7697SMichael.Christensen@Sun.COM } 1467*7697SMichael.Christensen@Sun.COM 1468*7697SMichael.Christensen@Sun.COM nack = (ds_unreg_nack_t *)(buf + DS_HDR_SZ); 1469*7697SMichael.Christensen@Sun.COM 1470*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_nack: hdl=0x%llx" DS_EOL, 1471*7697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)nack->svc_handle); 1472*7697SMichael.Christensen@Sun.COM 1473*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 1474*7697SMichael.Christensen@Sun.COM 1475*7697SMichael.Christensen@Sun.COM /* 1476*7697SMichael.Christensen@Sun.COM * Since the unregister request was initiated locally, 1477*7697SMichael.Christensen@Sun.COM * the service structure has already been torn down. 1478*7697SMichael.Christensen@Sun.COM * Just perform a sanity check to make sure the message 1479*7697SMichael.Christensen@Sun.COM * is appropriate. 1480*7697SMichael.Christensen@Sun.COM */ 1481*7697SMichael.Christensen@Sun.COM if (ds_get_svc(nack->svc_handle) != NULL) { 1482*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_nack: handle 0x%llx in use" 1483*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 1484*7697SMichael.Christensen@Sun.COM } 1485*7697SMichael.Christensen@Sun.COM 1486*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1487*7697SMichael.Christensen@Sun.COM } 1488*7697SMichael.Christensen@Sun.COM 1489*7697SMichael.Christensen@Sun.COM static void 1490*7697SMichael.Christensen@Sun.COM ds_handle_data(ds_port_t *port, caddr_t buf, size_t len) 1491*7697SMichael.Christensen@Sun.COM { 1492*7697SMichael.Christensen@Sun.COM ds_data_handle_t *data; 1493*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 1494*7697SMichael.Christensen@Sun.COM char *msg; 1495*7697SMichael.Christensen@Sun.COM int msgsz; 1496*7697SMichael.Christensen@Sun.COM int hdrsz; 1497*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_data_handle_t); 1498*7697SMichael.Christensen@Sun.COM 1499*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 1500*7697SMichael.Christensen@Sun.COM if (len < explen) { 1501*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data: invalid message length " 1502*7697SMichael.Christensen@Sun.COM "(%ld), expected at least %ld" DS_EOL, PORTID(port), len, 1503*7697SMichael.Christensen@Sun.COM explen); 1504*7697SMichael.Christensen@Sun.COM return; 1505*7697SMichael.Christensen@Sun.COM } 1506*7697SMichael.Christensen@Sun.COM 1507*7697SMichael.Christensen@Sun.COM data = (ds_data_handle_t *)(buf + DS_HDR_SZ); 1508*7697SMichael.Christensen@Sun.COM 1509*7697SMichael.Christensen@Sun.COM hdrsz = DS_HDR_SZ + sizeof (ds_data_handle_t); 1510*7697SMichael.Christensen@Sun.COM msgsz = len - hdrsz; 1511*7697SMichael.Christensen@Sun.COM 1512*7697SMichael.Christensen@Sun.COM /* strip off the header for the client */ 1513*7697SMichael.Christensen@Sun.COM msg = (msgsz) ? (buf + hdrsz) : NULL; 1514*7697SMichael.Christensen@Sun.COM 1515*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 1516*7697SMichael.Christensen@Sun.COM 1517*7697SMichael.Christensen@Sun.COM if ((svc = ds_find_clnt_svc_by_hdl_port(data->svc_handle, port)) 1518*7697SMichael.Christensen@Sun.COM == NULL) { 1519*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(data->svc_handle)) == NULL) { 1520*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1521*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data: invalid handle 0x%llx" 1522*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), 1523*7697SMichael.Christensen@Sun.COM (u_longlong_t)data->svc_handle); 1524*7697SMichael.Christensen@Sun.COM ds_send_data_nack(port, data->svc_handle); 1525*7697SMichael.Christensen@Sun.COM return; 1526*7697SMichael.Christensen@Sun.COM } 1527*7697SMichael.Christensen@Sun.COM } 1528*7697SMichael.Christensen@Sun.COM 1529*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1530*7697SMichael.Christensen@Sun.COM 1531*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <data: '%s' hdl=0x%llx" DS_EOL, 1532*7697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)svc->hdl); 1533*7697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msgsz); 1534*7697SMichael.Christensen@Sun.COM 1535*7697SMichael.Christensen@Sun.COM /* dispatch this message to the client */ 1536*7697SMichael.Christensen@Sun.COM (*svc->ops.ds_data_cb)(svc->ops.cb_arg, msg, msgsz); 1537*7697SMichael.Christensen@Sun.COM } 1538*7697SMichael.Christensen@Sun.COM 1539*7697SMichael.Christensen@Sun.COM static void 1540*7697SMichael.Christensen@Sun.COM ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len) 1541*7697SMichael.Christensen@Sun.COM { 1542*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 1543*7697SMichael.Christensen@Sun.COM ds_data_nack_t *nack; 1544*7697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_data_nack_t); 1545*7697SMichael.Christensen@Sun.COM 1546*7697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 1547*7697SMichael.Christensen@Sun.COM if (len != explen) { 1548*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data_nack: invalid message " 1549*7697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 1550*7697SMichael.Christensen@Sun.COM explen); 1551*7697SMichael.Christensen@Sun.COM return; 1552*7697SMichael.Christensen@Sun.COM } 1553*7697SMichael.Christensen@Sun.COM 1554*7697SMichael.Christensen@Sun.COM nack = (ds_data_nack_t *)(buf + DS_HDR_SZ); 1555*7697SMichael.Christensen@Sun.COM 1556*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack: hdl=0x%llx, result=0x%llx" 1557*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle, 1558*7697SMichael.Christensen@Sun.COM (u_longlong_t)nack->result); 1559*7697SMichael.Christensen@Sun.COM 1560*7697SMichael.Christensen@Sun.COM if (nack->result == DS_INV_HDL) { 1561*7697SMichael.Christensen@Sun.COM 1562*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 1563*7697SMichael.Christensen@Sun.COM 1564*7697SMichael.Christensen@Sun.COM if ((svc = ds_find_clnt_svc_by_hdl_port(nack->svc_handle, 1565*7697SMichael.Christensen@Sun.COM port)) == NULL) { 1566*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(nack->svc_handle)) == NULL) { 1567*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1568*7697SMichael.Christensen@Sun.COM return; 1569*7697SMichael.Christensen@Sun.COM } 1570*7697SMichael.Christensen@Sun.COM } 1571*7697SMichael.Christensen@Sun.COM 1572*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data_nack: handle 0x%llx reported " 1573*7697SMichael.Christensen@Sun.COM " as invalid" DS_EOL, PORTID(port), 1574*7697SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle); 1575*7697SMichael.Christensen@Sun.COM 1576*7697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 1577*7697SMichael.Christensen@Sun.COM 1578*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 1579*7697SMichael.Christensen@Sun.COM } 1580*7697SMichael.Christensen@Sun.COM } 1581*7697SMichael.Christensen@Sun.COM 1582*7697SMichael.Christensen@Sun.COM /* Initialize the port */ 1583*7697SMichael.Christensen@Sun.COM void 1584*7697SMichael.Christensen@Sun.COM ds_send_init_req(ds_port_t *port) 1585*7697SMichael.Christensen@Sun.COM { 1586*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 1587*7697SMichael.Christensen@Sun.COM ds_init_req_t *init_req; 1588*7697SMichael.Christensen@Sun.COM size_t msglen; 1589*7697SMichael.Christensen@Sun.COM ds_ver_t *vers = &ds_vers[port->ver_idx]; 1590*7697SMichael.Christensen@Sun.COM 1591*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 1592*7697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_LDC_INIT) { 1593*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: invalid state: %d" 1594*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 1595*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1596*7697SMichael.Christensen@Sun.COM return; 1597*7697SMichael.Christensen@Sun.COM } 1598*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1599*7697SMichael.Christensen@Sun.COM 1600*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: req=v%d.%d" DS_EOL, 1601*7697SMichael.Christensen@Sun.COM PORTID(port), vers->major, vers->minor); 1602*7697SMichael.Christensen@Sun.COM 1603*7697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_init_req_t); 1604*7697SMichael.Christensen@Sun.COM hdr = DS_MALLOC(msglen); 1605*7697SMichael.Christensen@Sun.COM 1606*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_REQ; 1607*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_req_t); 1608*7697SMichael.Christensen@Sun.COM 1609*7697SMichael.Christensen@Sun.COM init_req = (ds_init_req_t *)((caddr_t)hdr + DS_HDR_SZ); 1610*7697SMichael.Christensen@Sun.COM init_req->major_vers = vers->major; 1611*7697SMichael.Christensen@Sun.COM init_req->minor_vers = vers->minor; 1612*7697SMichael.Christensen@Sun.COM 1613*7697SMichael.Christensen@Sun.COM if (ds_send_msg(port, (caddr_t)hdr, msglen) == 0) { 1614*7697SMichael.Christensen@Sun.COM /* 1615*7697SMichael.Christensen@Sun.COM * We've left the port state unlocked over the malloc/send, 1616*7697SMichael.Christensen@Sun.COM * make sure no one has changed the state under us before 1617*7697SMichael.Christensen@Sun.COM * we update the state. 1618*7697SMichael.Christensen@Sun.COM */ 1619*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 1620*7697SMichael.Christensen@Sun.COM if (port->state == DS_PORT_LDC_INIT) 1621*7697SMichael.Christensen@Sun.COM port->state = DS_PORT_INIT_REQ; 1622*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1623*7697SMichael.Christensen@Sun.COM } 1624*7697SMichael.Christensen@Sun.COM DS_FREE(hdr, msglen); 1625*7697SMichael.Christensen@Sun.COM } 1626*7697SMichael.Christensen@Sun.COM 1627*7697SMichael.Christensen@Sun.COM static int 1628*7697SMichael.Christensen@Sun.COM ds_send_reg_req(ds_svc_t *svc, ds_port_t *port) 1629*7697SMichael.Christensen@Sun.COM { 1630*7697SMichael.Christensen@Sun.COM ds_ver_t *ver; 1631*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 1632*7697SMichael.Christensen@Sun.COM caddr_t msg; 1633*7697SMichael.Christensen@Sun.COM size_t msglen; 1634*7697SMichael.Christensen@Sun.COM ds_reg_req_t *req; 1635*7697SMichael.Christensen@Sun.COM size_t idlen; 1636*7697SMichael.Christensen@Sun.COM int rv; 1637*7697SMichael.Christensen@Sun.COM 1638*7697SMichael.Christensen@Sun.COM ASSERT(svc->state == DS_SVC_INACTIVE || 1639*7697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) != 0); 1640*7697SMichael.Christensen@Sun.COM 1641*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 1642*7697SMichael.Christensen@Sun.COM 1643*7697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 1644*7697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 1645*7697SMichael.Christensen@Sun.COM /* can not send message */ 1646*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: channel %ld is not up" 1647*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 1648*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1649*7697SMichael.Christensen@Sun.COM return (-1); 1650*7697SMichael.Christensen@Sun.COM } 1651*7697SMichael.Christensen@Sun.COM 1652*7697SMichael.Christensen@Sun.COM /* make sure port is ready */ 1653*7697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 1654*7697SMichael.Christensen@Sun.COM /* can not send message */ 1655*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: port is not ready" 1656*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 1657*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1658*7697SMichael.Christensen@Sun.COM return (-1); 1659*7697SMichael.Christensen@Sun.COM } 1660*7697SMichael.Christensen@Sun.COM 1661*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1662*7697SMichael.Christensen@Sun.COM 1663*7697SMichael.Christensen@Sun.COM /* allocate the message buffer */ 1664*7697SMichael.Christensen@Sun.COM idlen = strlen(svc->cap.svc_id); 1665*7697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_reg_req_t) + idlen; 1666*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 1667*7697SMichael.Christensen@Sun.COM 1668*7697SMichael.Christensen@Sun.COM /* copy in the header data */ 1669*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 1670*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_REQ; 1671*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_req_t) + idlen; 1672*7697SMichael.Christensen@Sun.COM 1673*7697SMichael.Christensen@Sun.COM req = (ds_reg_req_t *)(msg + DS_HDR_SZ); 1674*7697SMichael.Christensen@Sun.COM req->svc_handle = svc->hdl; 1675*7697SMichael.Christensen@Sun.COM ver = &(svc->cap.vers[svc->ver_idx]); 1676*7697SMichael.Christensen@Sun.COM req->major_vers = ver->major; 1677*7697SMichael.Christensen@Sun.COM req->minor_vers = ver->minor; 1678*7697SMichael.Christensen@Sun.COM 1679*7697SMichael.Christensen@Sun.COM /* copy in the service id */ 1680*7697SMichael.Christensen@Sun.COM (void) memcpy(req->svc_id, svc->cap.svc_id, idlen + 1); 1681*7697SMichael.Christensen@Sun.COM 1682*7697SMichael.Christensen@Sun.COM /* send the message */ 1683*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: '%s' ver=%d.%d, hdl=0x%llx" 1684*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, ver->major, ver->minor, 1685*7697SMichael.Christensen@Sun.COM (u_longlong_t)svc->hdl); 1686*7697SMichael.Christensen@Sun.COM 1687*7697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 1688*7697SMichael.Christensen@Sun.COM svc->port = port; 1689*7697SMichael.Christensen@Sun.COM rv = -1; 1690*7697SMichael.Christensen@Sun.COM } else if ((svc->flags & DSSF_ISCLIENT) == 0) { 1691*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_REG_PENDING; 1692*7697SMichael.Christensen@Sun.COM } 1693*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 1694*7697SMichael.Christensen@Sun.COM 1695*7697SMichael.Christensen@Sun.COM return (rv); 1696*7697SMichael.Christensen@Sun.COM } 1697*7697SMichael.Christensen@Sun.COM 1698*7697SMichael.Christensen@Sun.COM /* 1699*7697SMichael.Christensen@Sun.COM * Keep around in case we want this later 1700*7697SMichael.Christensen@Sun.COM */ 1701*7697SMichael.Christensen@Sun.COM int 1702*7697SMichael.Christensen@Sun.COM ds_send_unreg_req(ds_svc_t *svc) 1703*7697SMichael.Christensen@Sun.COM { 1704*7697SMichael.Christensen@Sun.COM caddr_t msg; 1705*7697SMichael.Christensen@Sun.COM size_t msglen; 1706*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 1707*7697SMichael.Christensen@Sun.COM ds_unreg_req_t *req; 1708*7697SMichael.Christensen@Sun.COM ds_port_t *port = svc->port; 1709*7697SMichael.Christensen@Sun.COM int rv; 1710*7697SMichael.Christensen@Sun.COM 1711*7697SMichael.Christensen@Sun.COM if (port == NULL) { 1712*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "send_unreg_req: service '%s' not " 1713*7697SMichael.Christensen@Sun.COM "associated with a port" DS_EOL, svc->cap.svc_id); 1714*7697SMichael.Christensen@Sun.COM return (-1); 1715*7697SMichael.Christensen@Sun.COM } 1716*7697SMichael.Christensen@Sun.COM 1717*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 1718*7697SMichael.Christensen@Sun.COM 1719*7697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 1720*7697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 1721*7697SMichael.Christensen@Sun.COM /* can not send message */ 1722*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_req>: channel %ld is not up" 1723*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 1724*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1725*7697SMichael.Christensen@Sun.COM return (-1); 1726*7697SMichael.Christensen@Sun.COM } 1727*7697SMichael.Christensen@Sun.COM 1728*7697SMichael.Christensen@Sun.COM /* make sure port is ready */ 1729*7697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 1730*7697SMichael.Christensen@Sun.COM /* can not send message */ 1731*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_req>: port is not ready" DS_EOL, 1732*7697SMichael.Christensen@Sun.COM PORTID(port)); 1733*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1734*7697SMichael.Christensen@Sun.COM return (-1); 1735*7697SMichael.Christensen@Sun.COM } 1736*7697SMichael.Christensen@Sun.COM 1737*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1738*7697SMichael.Christensen@Sun.COM 1739*7697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_req_t); 1740*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 1741*7697SMichael.Christensen@Sun.COM 1742*7697SMichael.Christensen@Sun.COM /* copy in the header data */ 1743*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 1744*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG; 1745*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_req_t); 1746*7697SMichael.Christensen@Sun.COM 1747*7697SMichael.Christensen@Sun.COM req = (ds_unreg_req_t *)(msg + DS_HDR_SZ); 1748*7697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 1749*7697SMichael.Christensen@Sun.COM req->svc_handle = svc->svc_hdl; 1750*7697SMichael.Christensen@Sun.COM } else { 1751*7697SMichael.Christensen@Sun.COM req->svc_handle = svc->hdl; 1752*7697SMichael.Christensen@Sun.COM } 1753*7697SMichael.Christensen@Sun.COM 1754*7697SMichael.Christensen@Sun.COM /* send the message */ 1755*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_req>: '%s' hdl=0x%llx" DS_EOL, 1756*7697SMichael.Christensen@Sun.COM PORTID(port), (svc->cap.svc_id) ? svc->cap.svc_id : "NULL", 1757*7697SMichael.Christensen@Sun.COM (u_longlong_t)svc->hdl); 1758*7697SMichael.Christensen@Sun.COM 1759*7697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 1760*7697SMichael.Christensen@Sun.COM rv = -1; 1761*7697SMichael.Christensen@Sun.COM } 1762*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 1763*7697SMichael.Christensen@Sun.COM 1764*7697SMichael.Christensen@Sun.COM return (rv); 1765*7697SMichael.Christensen@Sun.COM } 1766*7697SMichael.Christensen@Sun.COM 1767*7697SMichael.Christensen@Sun.COM static void 1768*7697SMichael.Christensen@Sun.COM ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl) 1769*7697SMichael.Christensen@Sun.COM { 1770*7697SMichael.Christensen@Sun.COM caddr_t msg; 1771*7697SMichael.Christensen@Sun.COM size_t msglen; 1772*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 1773*7697SMichael.Christensen@Sun.COM ds_unreg_nack_t *nack; 1774*7697SMichael.Christensen@Sun.COM 1775*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 1776*7697SMichael.Christensen@Sun.COM 1777*7697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 1778*7697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 1779*7697SMichael.Christensen@Sun.COM /* can not send message */ 1780*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_nack>: channel %ld is not up" 1781*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 1782*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1783*7697SMichael.Christensen@Sun.COM return; 1784*7697SMichael.Christensen@Sun.COM } 1785*7697SMichael.Christensen@Sun.COM 1786*7697SMichael.Christensen@Sun.COM /* make sure port is ready */ 1787*7697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 1788*7697SMichael.Christensen@Sun.COM /* can not send message */ 1789*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_nack>: port is not ready" 1790*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 1791*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1792*7697SMichael.Christensen@Sun.COM return; 1793*7697SMichael.Christensen@Sun.COM } 1794*7697SMichael.Christensen@Sun.COM 1795*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1796*7697SMichael.Christensen@Sun.COM 1797*7697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_nack_t); 1798*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 1799*7697SMichael.Christensen@Sun.COM 1800*7697SMichael.Christensen@Sun.COM /* copy in the header data */ 1801*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 1802*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG_NACK; 1803*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_nack_t); 1804*7697SMichael.Christensen@Sun.COM 1805*7697SMichael.Christensen@Sun.COM nack = (ds_unreg_nack_t *)(msg + DS_HDR_SZ); 1806*7697SMichael.Christensen@Sun.COM nack->svc_handle = bad_hdl; 1807*7697SMichael.Christensen@Sun.COM 1808*7697SMichael.Christensen@Sun.COM /* send the message */ 1809*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_nack>: hdl=0x%llx" DS_EOL, 1810*7697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)bad_hdl); 1811*7697SMichael.Christensen@Sun.COM 1812*7697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 1813*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 1814*7697SMichael.Christensen@Sun.COM } 1815*7697SMichael.Christensen@Sun.COM 1816*7697SMichael.Christensen@Sun.COM static void 1817*7697SMichael.Christensen@Sun.COM ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl) 1818*7697SMichael.Christensen@Sun.COM { 1819*7697SMichael.Christensen@Sun.COM caddr_t msg; 1820*7697SMichael.Christensen@Sun.COM size_t msglen; 1821*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 1822*7697SMichael.Christensen@Sun.COM ds_data_nack_t *nack; 1823*7697SMichael.Christensen@Sun.COM 1824*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 1825*7697SMichael.Christensen@Sun.COM 1826*7697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 1827*7697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 1828*7697SMichael.Christensen@Sun.COM /* can not send message */ 1829*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: data_nack>: channel %ld is not up" 1830*7697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 1831*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1832*7697SMichael.Christensen@Sun.COM return; 1833*7697SMichael.Christensen@Sun.COM } 1834*7697SMichael.Christensen@Sun.COM 1835*7697SMichael.Christensen@Sun.COM /* make sure port is ready */ 1836*7697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 1837*7697SMichael.Christensen@Sun.COM /* can not send message */ 1838*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: data_nack>: port is not ready" DS_EOL, 1839*7697SMichael.Christensen@Sun.COM PORTID(port)); 1840*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1841*7697SMichael.Christensen@Sun.COM return; 1842*7697SMichael.Christensen@Sun.COM } 1843*7697SMichael.Christensen@Sun.COM 1844*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 1845*7697SMichael.Christensen@Sun.COM 1846*7697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_data_nack_t); 1847*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 1848*7697SMichael.Christensen@Sun.COM 1849*7697SMichael.Christensen@Sun.COM /* copy in the header data */ 1850*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 1851*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_NACK; 1852*7697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_data_nack_t); 1853*7697SMichael.Christensen@Sun.COM 1854*7697SMichael.Christensen@Sun.COM nack = (ds_data_nack_t *)(msg + DS_HDR_SZ); 1855*7697SMichael.Christensen@Sun.COM nack->svc_handle = bad_hdl; 1856*7697SMichael.Christensen@Sun.COM nack->result = DS_INV_HDL; 1857*7697SMichael.Christensen@Sun.COM 1858*7697SMichael.Christensen@Sun.COM /* send the message */ 1859*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack>: hdl=0x%llx" DS_EOL, 1860*7697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)bad_hdl); 1861*7697SMichael.Christensen@Sun.COM 1862*7697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 1863*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 1864*7697SMichael.Christensen@Sun.COM } 1865*7697SMichael.Christensen@Sun.COM 1866*7697SMichael.Christensen@Sun.COM /* END DS PROTOCOL SUPPORT FUNCTIONS */ 1867*7697SMichael.Christensen@Sun.COM 1868*7697SMichael.Christensen@Sun.COM #ifdef DEBUG 1869*7697SMichael.Christensen@Sun.COM 1870*7697SMichael.Christensen@Sun.COM #define BYTESPERLINE 8 1871*7697SMichael.Christensen@Sun.COM #define LINEWIDTH ((BYTESPERLINE * 3) + (BYTESPERLINE + 2) + 1) 1872*7697SMichael.Christensen@Sun.COM #define ASCIIOFFSET ((BYTESPERLINE * 3) + 2) 1873*7697SMichael.Christensen@Sun.COM #define ISPRINT(c) ((c >= ' ') && (c <= '~')) 1874*7697SMichael.Christensen@Sun.COM 1875*7697SMichael.Christensen@Sun.COM /* 1876*7697SMichael.Christensen@Sun.COM * Output a buffer formatted with a set number of bytes on 1877*7697SMichael.Christensen@Sun.COM * each line. Append each line with the ASCII equivalent of 1878*7697SMichael.Christensen@Sun.COM * each byte if it falls within the printable ASCII range, 1879*7697SMichael.Christensen@Sun.COM * and '.' otherwise. 1880*7697SMichael.Christensen@Sun.COM */ 1881*7697SMichael.Christensen@Sun.COM void 1882*7697SMichael.Christensen@Sun.COM ds_dump_msg(void *vbuf, size_t len) 1883*7697SMichael.Christensen@Sun.COM { 1884*7697SMichael.Christensen@Sun.COM int i, j; 1885*7697SMichael.Christensen@Sun.COM char *curr; 1886*7697SMichael.Christensen@Sun.COM char *aoff; 1887*7697SMichael.Christensen@Sun.COM char line[LINEWIDTH]; 1888*7697SMichael.Christensen@Sun.COM uint8_t *buf = vbuf; 1889*7697SMichael.Christensen@Sun.COM 1890*7697SMichael.Christensen@Sun.COM if (len > 128) 1891*7697SMichael.Christensen@Sun.COM len = 128; 1892*7697SMichael.Christensen@Sun.COM 1893*7697SMichael.Christensen@Sun.COM /* walk the buffer one line at a time */ 1894*7697SMichael.Christensen@Sun.COM for (i = 0; i < len; i += BYTESPERLINE) { 1895*7697SMichael.Christensen@Sun.COM 1896*7697SMichael.Christensen@Sun.COM bzero(line, LINEWIDTH); 1897*7697SMichael.Christensen@Sun.COM 1898*7697SMichael.Christensen@Sun.COM curr = line; 1899*7697SMichael.Christensen@Sun.COM aoff = line + ASCIIOFFSET; 1900*7697SMichael.Christensen@Sun.COM 1901*7697SMichael.Christensen@Sun.COM /* 1902*7697SMichael.Christensen@Sun.COM * Walk the bytes in the current line, storing 1903*7697SMichael.Christensen@Sun.COM * the hex value for the byte as well as the 1904*7697SMichael.Christensen@Sun.COM * ASCII representation in a temporary buffer. 1905*7697SMichael.Christensen@Sun.COM * All ASCII values are placed at the end of 1906*7697SMichael.Christensen@Sun.COM * the line. 1907*7697SMichael.Christensen@Sun.COM */ 1908*7697SMichael.Christensen@Sun.COM for (j = 0; (j < BYTESPERLINE) && ((i + j) < len); j++) { 1909*7697SMichael.Christensen@Sun.COM (void) sprintf(curr, " %02x", buf[i + j]); 1910*7697SMichael.Christensen@Sun.COM *aoff = (ISPRINT(buf[i + j])) ? buf[i + j] : '.'; 1911*7697SMichael.Christensen@Sun.COM curr += 3; 1912*7697SMichael.Christensen@Sun.COM aoff++; 1913*7697SMichael.Christensen@Sun.COM } 1914*7697SMichael.Christensen@Sun.COM 1915*7697SMichael.Christensen@Sun.COM /* 1916*7697SMichael.Christensen@Sun.COM * Fill in to the start of the ASCII translation 1917*7697SMichael.Christensen@Sun.COM * with spaces. This will only be necessary if 1918*7697SMichael.Christensen@Sun.COM * this is the last line and there are not enough 1919*7697SMichael.Christensen@Sun.COM * bytes to fill the whole line. 1920*7697SMichael.Christensen@Sun.COM */ 1921*7697SMichael.Christensen@Sun.COM while (curr != (line + ASCIIOFFSET)) 1922*7697SMichael.Christensen@Sun.COM *curr++ = ' '; 1923*7697SMichael.Christensen@Sun.COM 1924*7697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s" DS_EOL, line); 1925*7697SMichael.Christensen@Sun.COM } 1926*7697SMichael.Christensen@Sun.COM } 1927*7697SMichael.Christensen@Sun.COM #endif /* DEBUG */ 1928*7697SMichael.Christensen@Sun.COM 1929*7697SMichael.Christensen@Sun.COM 1930*7697SMichael.Christensen@Sun.COM /* 1931*7697SMichael.Christensen@Sun.COM * Walk the table of registered services, executing the specified callback 1932*7697SMichael.Christensen@Sun.COM * function for each service on a port. A non-zero return value from the 1933*7697SMichael.Christensen@Sun.COM * callback is used to terminate the walk, not to indicate an error. Returns 1934*7697SMichael.Christensen@Sun.COM * the index of the last service visited. 1935*7697SMichael.Christensen@Sun.COM */ 1936*7697SMichael.Christensen@Sun.COM int 1937*7697SMichael.Christensen@Sun.COM ds_walk_svcs(svc_cb_t svc_cb, void *arg) 1938*7697SMichael.Christensen@Sun.COM { 1939*7697SMichael.Christensen@Sun.COM int idx; 1940*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 1941*7697SMichael.Christensen@Sun.COM 1942*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 1943*7697SMichael.Christensen@Sun.COM 1944*7697SMichael.Christensen@Sun.COM /* walk every table entry */ 1945*7697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 1946*7697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 1947*7697SMichael.Christensen@Sun.COM 1948*7697SMichael.Christensen@Sun.COM /* execute the callback */ 1949*7697SMichael.Christensen@Sun.COM if ((*svc_cb)(svc, arg) != 0) 1950*7697SMichael.Christensen@Sun.COM break; 1951*7697SMichael.Christensen@Sun.COM } 1952*7697SMichael.Christensen@Sun.COM 1953*7697SMichael.Christensen@Sun.COM return (idx); 1954*7697SMichael.Christensen@Sun.COM } 1955*7697SMichael.Christensen@Sun.COM 1956*7697SMichael.Christensen@Sun.COM static int 1957*7697SMichael.Christensen@Sun.COM ds_svc_isfree(ds_svc_t *svc, void *arg) 1958*7697SMichael.Christensen@Sun.COM { 1959*7697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 1960*7697SMichael.Christensen@Sun.COM 1961*7697SMichael.Christensen@Sun.COM /* 1962*7697SMichael.Christensen@Sun.COM * Looking for a free service. This may be a NULL entry 1963*7697SMichael.Christensen@Sun.COM * in the table, or an unused structure that could be 1964*7697SMichael.Christensen@Sun.COM * reused. 1965*7697SMichael.Christensen@Sun.COM */ 1966*7697SMichael.Christensen@Sun.COM 1967*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 1968*7697SMichael.Christensen@Sun.COM /* yes, it is free */ 1969*7697SMichael.Christensen@Sun.COM return (1); 1970*7697SMichael.Christensen@Sun.COM } 1971*7697SMichael.Christensen@Sun.COM 1972*7697SMichael.Christensen@Sun.COM /* not a candidate */ 1973*7697SMichael.Christensen@Sun.COM return (0); 1974*7697SMichael.Christensen@Sun.COM } 1975*7697SMichael.Christensen@Sun.COM 1976*7697SMichael.Christensen@Sun.COM int 1977*7697SMichael.Christensen@Sun.COM ds_svc_ismatch(ds_svc_t *svc, void *arg) 1978*7697SMichael.Christensen@Sun.COM { 1979*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 1980*7697SMichael.Christensen@Sun.COM return (0); 1981*7697SMichael.Christensen@Sun.COM } 1982*7697SMichael.Christensen@Sun.COM 1983*7697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, arg) == 0 && 1984*7697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) == 0) { 1985*7697SMichael.Christensen@Sun.COM /* found a match */ 1986*7697SMichael.Christensen@Sun.COM return (1); 1987*7697SMichael.Christensen@Sun.COM } 1988*7697SMichael.Christensen@Sun.COM 1989*7697SMichael.Christensen@Sun.COM return (0); 1990*7697SMichael.Christensen@Sun.COM } 1991*7697SMichael.Christensen@Sun.COM 1992*7697SMichael.Christensen@Sun.COM int 1993*7697SMichael.Christensen@Sun.COM ds_svc_clnt_ismatch(ds_svc_t *svc, void *arg) 1994*7697SMichael.Christensen@Sun.COM { 1995*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 1996*7697SMichael.Christensen@Sun.COM return (0); 1997*7697SMichael.Christensen@Sun.COM } 1998*7697SMichael.Christensen@Sun.COM 1999*7697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, arg) == 0 && 2000*7697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) != 0) { 2001*7697SMichael.Christensen@Sun.COM /* found a match */ 2002*7697SMichael.Christensen@Sun.COM return (1); 2003*7697SMichael.Christensen@Sun.COM } 2004*7697SMichael.Christensen@Sun.COM 2005*7697SMichael.Christensen@Sun.COM return (0); 2006*7697SMichael.Christensen@Sun.COM } 2007*7697SMichael.Christensen@Sun.COM 2008*7697SMichael.Christensen@Sun.COM int 2009*7697SMichael.Christensen@Sun.COM ds_svc_free(ds_svc_t *svc, void *arg) 2010*7697SMichael.Christensen@Sun.COM { 2011*7697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 2012*7697SMichael.Christensen@Sun.COM 2013*7697SMichael.Christensen@Sun.COM if (svc == NULL) { 2014*7697SMichael.Christensen@Sun.COM return (0); 2015*7697SMichael.Christensen@Sun.COM } 2016*7697SMichael.Christensen@Sun.COM 2017*7697SMichael.Christensen@Sun.COM if (svc->cap.svc_id) { 2018*7697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1); 2019*7697SMichael.Christensen@Sun.COM svc->cap.svc_id = NULL; 2020*7697SMichael.Christensen@Sun.COM } 2021*7697SMichael.Christensen@Sun.COM 2022*7697SMichael.Christensen@Sun.COM if (svc->cap.vers) { 2023*7697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t)); 2024*7697SMichael.Christensen@Sun.COM svc->cap.vers = NULL; 2025*7697SMichael.Christensen@Sun.COM } 2026*7697SMichael.Christensen@Sun.COM 2027*7697SMichael.Christensen@Sun.COM DS_FREE(svc, sizeof (ds_svc_t)); 2028*7697SMichael.Christensen@Sun.COM 2029*7697SMichael.Christensen@Sun.COM return (0); 2030*7697SMichael.Christensen@Sun.COM } 2031*7697SMichael.Christensen@Sun.COM 2032*7697SMichael.Christensen@Sun.COM static int 2033*7697SMichael.Christensen@Sun.COM ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port) 2034*7697SMichael.Christensen@Sun.COM { 2035*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2036*7697SMichael.Christensen@Sun.COM 2037*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 2038*7697SMichael.Christensen@Sun.COM return (0); 2039*7697SMichael.Christensen@Sun.COM 2040*7697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(svc->avail, PORTID(port))) 2041*7697SMichael.Christensen@Sun.COM return (0); 2042*7697SMichael.Christensen@Sun.COM 2043*7697SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->tried, PORTID(port)); 2044*7697SMichael.Christensen@Sun.COM 2045*7697SMichael.Christensen@Sun.COM if (ds_send_reg_req(svc, port) == 0) { 2046*7697SMichael.Christensen@Sun.COM /* register sent successfully */ 2047*7697SMichael.Christensen@Sun.COM return (1); 2048*7697SMichael.Christensen@Sun.COM } 2049*7697SMichael.Christensen@Sun.COM 2050*7697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) { 2051*7697SMichael.Christensen@Sun.COM /* reset the service */ 2052*7697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 2053*7697SMichael.Christensen@Sun.COM } 2054*7697SMichael.Christensen@Sun.COM return (0); 2055*7697SMichael.Christensen@Sun.COM } 2056*7697SMichael.Christensen@Sun.COM 2057*7697SMichael.Christensen@Sun.COM int 2058*7697SMichael.Christensen@Sun.COM ds_svc_register(ds_svc_t *svc, void *arg) 2059*7697SMichael.Christensen@Sun.COM { 2060*7697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 2061*7697SMichael.Christensen@Sun.COM ds_portset_t ports; 2062*7697SMichael.Christensen@Sun.COM ds_port_t *port; 2063*7697SMichael.Christensen@Sun.COM int idx; 2064*7697SMichael.Christensen@Sun.COM 2065*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2066*7697SMichael.Christensen@Sun.COM 2067*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 2068*7697SMichael.Christensen@Sun.COM return (0); 2069*7697SMichael.Christensen@Sun.COM 2070*7697SMichael.Christensen@Sun.COM ports = svc->avail; 2071*7697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 2072*7697SMichael.Christensen@Sun.COM ds_portset_del_active_clients(svc->cap.svc_id, &ports); 2073*7697SMichael.Christensen@Sun.COM } else if (svc->state != DS_SVC_INACTIVE) 2074*7697SMichael.Christensen@Sun.COM return (0); 2075*7697SMichael.Christensen@Sun.COM 2076*7697SMichael.Christensen@Sun.COM if (DS_PORTSET_ISNULL(ports)) 2077*7697SMichael.Christensen@Sun.COM return (0); 2078*7697SMichael.Christensen@Sun.COM 2079*7697SMichael.Christensen@Sun.COM /* 2080*7697SMichael.Christensen@Sun.COM * Attempt to register the service. Start with the lowest 2081*7697SMichael.Christensen@Sun.COM * numbered port and continue until a registration message 2082*7697SMichael.Christensen@Sun.COM * is sent successfully, or there are no ports left to try. 2083*7697SMichael.Christensen@Sun.COM */ 2084*7697SMichael.Christensen@Sun.COM for (idx = 0; idx < DS_MAX_PORTS; idx++) { 2085*7697SMichael.Christensen@Sun.COM 2086*7697SMichael.Christensen@Sun.COM /* 2087*7697SMichael.Christensen@Sun.COM * If the port is not in the available list, 2088*7697SMichael.Christensen@Sun.COM * it is not a candidate for registration. 2089*7697SMichael.Christensen@Sun.COM */ 2090*7697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(ports, idx)) { 2091*7697SMichael.Christensen@Sun.COM continue; 2092*7697SMichael.Christensen@Sun.COM } 2093*7697SMichael.Christensen@Sun.COM 2094*7697SMichael.Christensen@Sun.COM port = &ds_ports[idx]; 2095*7697SMichael.Christensen@Sun.COM if (ds_svc_register_onport(svc, port)) { 2096*7697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 2097*7697SMichael.Christensen@Sun.COM break; 2098*7697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(svc->avail, idx); 2099*7697SMichael.Christensen@Sun.COM } 2100*7697SMichael.Christensen@Sun.COM } 2101*7697SMichael.Christensen@Sun.COM 2102*7697SMichael.Christensen@Sun.COM return (0); 2103*7697SMichael.Christensen@Sun.COM } 2104*7697SMichael.Christensen@Sun.COM 2105*7697SMichael.Christensen@Sun.COM static int 2106*7697SMichael.Christensen@Sun.COM ds_svc_unregister(ds_svc_t *svc, void *arg) 2107*7697SMichael.Christensen@Sun.COM { 2108*7697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 2109*7697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 2110*7697SMichael.Christensen@Sun.COM 2111*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2112*7697SMichael.Christensen@Sun.COM 2113*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 2114*7697SMichael.Christensen@Sun.COM return (0); 2115*7697SMichael.Christensen@Sun.COM } 2116*7697SMichael.Christensen@Sun.COM 2117*7697SMichael.Christensen@Sun.COM /* make sure the service is using this port */ 2118*7697SMichael.Christensen@Sun.COM if (svc->port != port) { 2119*7697SMichael.Christensen@Sun.COM return (0); 2120*7697SMichael.Christensen@Sun.COM } 2121*7697SMichael.Christensen@Sun.COM 2122*7697SMichael.Christensen@Sun.COM if (port) { 2123*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: svc_unreg: id='%s', ver=%d.%d, " 2124*7697SMichael.Christensen@Sun.COM " hdl=0x%09lx" DS_EOL, PORTID(port), svc->cap.svc_id, 2125*7697SMichael.Christensen@Sun.COM svc->ver.major, svc->ver.minor, svc->hdl); 2126*7697SMichael.Christensen@Sun.COM } else { 2127*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "port=NULL: svc_unreg: id='%s', ver=%d.%d, " 2128*7697SMichael.Christensen@Sun.COM " hdl=0x%09lx" DS_EOL, svc->cap.svc_id, svc->ver.major, 2129*7697SMichael.Christensen@Sun.COM svc->ver.minor, svc->hdl); 2130*7697SMichael.Christensen@Sun.COM } 2131*7697SMichael.Christensen@Sun.COM 2132*7697SMichael.Christensen@Sun.COM /* reset the service structure */ 2133*7697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 2134*7697SMichael.Christensen@Sun.COM 2135*7697SMichael.Christensen@Sun.COM /* call the client unregister callback */ 2136*7697SMichael.Christensen@Sun.COM if (svc->ops.ds_unreg_cb) { 2137*7697SMichael.Christensen@Sun.COM (*svc->ops.ds_unreg_cb)(svc->ops.cb_arg); 2138*7697SMichael.Christensen@Sun.COM } 2139*7697SMichael.Christensen@Sun.COM 2140*7697SMichael.Christensen@Sun.COM /* increment the count in the handle to prevent reuse */ 2141*7697SMichael.Christensen@Sun.COM hdl = DS_ALLOC_HDL(DS_HDL2IDX(svc->hdl), DS_HDL2COUNT(svc->hdl)); 2142*7697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(svc->hdl)) { 2143*7697SMichael.Christensen@Sun.COM DS_HDL_SET_ISCLIENT(hdl); 2144*7697SMichael.Christensen@Sun.COM } 2145*7697SMichael.Christensen@Sun.COM svc->hdl = hdl; 2146*7697SMichael.Christensen@Sun.COM 2147*7697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_UNREG_PENDING) { 2148*7697SMichael.Christensen@Sun.COM /* try to initiate a new registration */ 2149*7697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 2150*7697SMichael.Christensen@Sun.COM } 2151*7697SMichael.Christensen@Sun.COM 2152*7697SMichael.Christensen@Sun.COM return (0); 2153*7697SMichael.Christensen@Sun.COM } 2154*7697SMichael.Christensen@Sun.COM 2155*7697SMichael.Christensen@Sun.COM static int 2156*7697SMichael.Christensen@Sun.COM ds_svc_port_up(ds_svc_t *svc, void *arg) 2157*7697SMichael.Christensen@Sun.COM { 2158*7697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 2159*7697SMichael.Christensen@Sun.COM 2160*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 2161*7697SMichael.Christensen@Sun.COM /* nothing to do */ 2162*7697SMichael.Christensen@Sun.COM return (0); 2163*7697SMichael.Christensen@Sun.COM } 2164*7697SMichael.Christensen@Sun.COM 2165*7697SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->avail, port->id); 2166*7697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(svc->tried, port->id); 2167*7697SMichael.Christensen@Sun.COM 2168*7697SMichael.Christensen@Sun.COM return (0); 2169*7697SMichael.Christensen@Sun.COM } 2170*7697SMichael.Christensen@Sun.COM 2171*7697SMichael.Christensen@Sun.COM ds_svc_t * 2172*7697SMichael.Christensen@Sun.COM ds_alloc_svc(void) 2173*7697SMichael.Christensen@Sun.COM { 2174*7697SMichael.Christensen@Sun.COM int idx; 2175*7697SMichael.Christensen@Sun.COM uint_t newmaxsvcs; 2176*7697SMichael.Christensen@Sun.COM ds_svc_t **newtbl; 2177*7697SMichael.Christensen@Sun.COM ds_svc_t *newsvc; 2178*7697SMichael.Christensen@Sun.COM 2179*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2180*7697SMichael.Christensen@Sun.COM 2181*7697SMichael.Christensen@Sun.COM idx = ds_walk_svcs(ds_svc_isfree, NULL); 2182*7697SMichael.Christensen@Sun.COM 2183*7697SMichael.Christensen@Sun.COM if (idx != ds_svcs.maxsvcs) { 2184*7697SMichael.Christensen@Sun.COM goto found; 2185*7697SMichael.Christensen@Sun.COM } 2186*7697SMichael.Christensen@Sun.COM 2187*7697SMichael.Christensen@Sun.COM /* 2188*7697SMichael.Christensen@Sun.COM * There was no free space in the table. Grow 2189*7697SMichael.Christensen@Sun.COM * the table to double its current size. 2190*7697SMichael.Christensen@Sun.COM */ 2191*7697SMichael.Christensen@Sun.COM newmaxsvcs = ds_svcs.maxsvcs * 2; 2192*7697SMichael.Christensen@Sun.COM newtbl = DS_MALLOC(newmaxsvcs * sizeof (ds_svc_t *)); 2193*7697SMichael.Christensen@Sun.COM 2194*7697SMichael.Christensen@Sun.COM /* copy old table data to the new table */ 2195*7697SMichael.Christensen@Sun.COM (void) memcpy(newtbl, ds_svcs.tbl, 2196*7697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs * sizeof (ds_svc_t *)); 2197*7697SMichael.Christensen@Sun.COM 2198*7697SMichael.Christensen@Sun.COM /* clean up the old table */ 2199*7697SMichael.Christensen@Sun.COM DS_FREE(ds_svcs.tbl, ds_svcs.maxsvcs * sizeof (ds_svc_t *)); 2200*7697SMichael.Christensen@Sun.COM ds_svcs.tbl = newtbl; 2201*7697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs = newmaxsvcs; 2202*7697SMichael.Christensen@Sun.COM 2203*7697SMichael.Christensen@Sun.COM /* search for a free space again */ 2204*7697SMichael.Christensen@Sun.COM idx = ds_walk_svcs(ds_svc_isfree, NULL); 2205*7697SMichael.Christensen@Sun.COM 2206*7697SMichael.Christensen@Sun.COM /* the table is locked so should find a free slot */ 2207*7697SMichael.Christensen@Sun.COM ASSERT(idx != ds_svcs.maxsvcs); 2208*7697SMichael.Christensen@Sun.COM 2209*7697SMichael.Christensen@Sun.COM found: 2210*7697SMichael.Christensen@Sun.COM /* allocate a new svc structure if necessary */ 2211*7697SMichael.Christensen@Sun.COM if ((newsvc = ds_svcs.tbl[idx]) == NULL) { 2212*7697SMichael.Christensen@Sun.COM /* allocate a new service */ 2213*7697SMichael.Christensen@Sun.COM newsvc = DS_MALLOC(sizeof (ds_svc_t)); 2214*7697SMichael.Christensen@Sun.COM ds_svcs.tbl[idx] = newsvc; 2215*7697SMichael.Christensen@Sun.COM } 2216*7697SMichael.Christensen@Sun.COM 2217*7697SMichael.Christensen@Sun.COM /* fill in the handle */ 2218*7697SMichael.Christensen@Sun.COM newsvc->hdl = DS_ALLOC_HDL(idx, DS_HDL2COUNT(newsvc->hdl)); 2219*7697SMichael.Christensen@Sun.COM newsvc->state = DS_SVC_FREE; /* Mark as free temporarily */ 2220*7697SMichael.Christensen@Sun.COM 2221*7697SMichael.Christensen@Sun.COM return (newsvc); 2222*7697SMichael.Christensen@Sun.COM } 2223*7697SMichael.Christensen@Sun.COM 2224*7697SMichael.Christensen@Sun.COM static void 2225*7697SMichael.Christensen@Sun.COM ds_reset_svc(ds_svc_t *svc, ds_port_t *port) 2226*7697SMichael.Christensen@Sun.COM { 2227*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2228*7697SMichael.Christensen@Sun.COM 2229*7697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_UNREG_PENDING) 2230*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 2231*7697SMichael.Christensen@Sun.COM svc->ver_idx = 0; 2232*7697SMichael.Christensen@Sun.COM svc->ver.major = 0; 2233*7697SMichael.Christensen@Sun.COM svc->ver.minor = 0; 2234*7697SMichael.Christensen@Sun.COM svc->port = NULL; 2235*7697SMichael.Christensen@Sun.COM if (port) { 2236*7697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(svc->avail, port->id); 2237*7697SMichael.Christensen@Sun.COM } 2238*7697SMichael.Christensen@Sun.COM } 2239*7697SMichael.Christensen@Sun.COM 2240*7697SMichael.Christensen@Sun.COM ds_svc_t * 2241*7697SMichael.Christensen@Sun.COM ds_get_svc(ds_svc_hdl_t hdl) 2242*7697SMichael.Christensen@Sun.COM { 2243*7697SMichael.Christensen@Sun.COM int idx; 2244*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2245*7697SMichael.Christensen@Sun.COM 2246*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2247*7697SMichael.Christensen@Sun.COM 2248*7697SMichael.Christensen@Sun.COM if (hdl == DS_INVALID_HDL) 2249*7697SMichael.Christensen@Sun.COM return (NULL); 2250*7697SMichael.Christensen@Sun.COM 2251*7697SMichael.Christensen@Sun.COM idx = DS_HDL2IDX(hdl); 2252*7697SMichael.Christensen@Sun.COM 2253*7697SMichael.Christensen@Sun.COM /* check if index is out of bounds */ 2254*7697SMichael.Christensen@Sun.COM if ((idx < 0) || (idx >= ds_svcs.maxsvcs)) 2255*7697SMichael.Christensen@Sun.COM return (NULL); 2256*7697SMichael.Christensen@Sun.COM 2257*7697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 2258*7697SMichael.Christensen@Sun.COM 2259*7697SMichael.Christensen@Sun.COM /* check for a valid service */ 2260*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 2261*7697SMichael.Christensen@Sun.COM return (NULL); 2262*7697SMichael.Christensen@Sun.COM 2263*7697SMichael.Christensen@Sun.COM /* make sure the handle is an exact match */ 2264*7697SMichael.Christensen@Sun.COM if (svc->hdl != hdl) 2265*7697SMichael.Christensen@Sun.COM return (NULL); 2266*7697SMichael.Christensen@Sun.COM 2267*7697SMichael.Christensen@Sun.COM return (svc); 2268*7697SMichael.Christensen@Sun.COM } 2269*7697SMichael.Christensen@Sun.COM 2270*7697SMichael.Christensen@Sun.COM static void 2271*7697SMichael.Christensen@Sun.COM ds_port_reset(ds_port_t *port) 2272*7697SMichael.Christensen@Sun.COM { 2273*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2274*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 2275*7697SMichael.Christensen@Sun.COM 2276*7697SMichael.Christensen@Sun.COM /* connection went down, mark everything inactive */ 2277*7697SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_unregister, port); 2278*7697SMichael.Christensen@Sun.COM 2279*7697SMichael.Christensen@Sun.COM port->ver_idx = 0; 2280*7697SMichael.Christensen@Sun.COM port->ver.major = 0; 2281*7697SMichael.Christensen@Sun.COM port->ver.minor = 0; 2282*7697SMichael.Christensen@Sun.COM port->state = DS_PORT_LDC_INIT; 2283*7697SMichael.Christensen@Sun.COM } 2284*7697SMichael.Christensen@Sun.COM 2285*7697SMichael.Christensen@Sun.COM /* 2286*7697SMichael.Christensen@Sun.COM * Verify that a version array is sorted as expected for the 2287*7697SMichael.Christensen@Sun.COM * version negotiation to work correctly. 2288*7697SMichael.Christensen@Sun.COM */ 2289*7697SMichael.Christensen@Sun.COM ds_vers_check_t 2290*7697SMichael.Christensen@Sun.COM ds_vers_isvalid(ds_ver_t *vers, int nvers) 2291*7697SMichael.Christensen@Sun.COM { 2292*7697SMichael.Christensen@Sun.COM uint16_t curr_major; 2293*7697SMichael.Christensen@Sun.COM uint16_t curr_minor; 2294*7697SMichael.Christensen@Sun.COM int idx; 2295*7697SMichael.Christensen@Sun.COM 2296*7697SMichael.Christensen@Sun.COM curr_major = vers[0].major; 2297*7697SMichael.Christensen@Sun.COM curr_minor = vers[0].minor; 2298*7697SMichael.Christensen@Sun.COM 2299*7697SMichael.Christensen@Sun.COM /* 2300*7697SMichael.Christensen@Sun.COM * Walk the version array, verifying correct ordering. 2301*7697SMichael.Christensen@Sun.COM * The array must be sorted from highest supported 2302*7697SMichael.Christensen@Sun.COM * version to lowest supported version. 2303*7697SMichael.Christensen@Sun.COM */ 2304*7697SMichael.Christensen@Sun.COM for (idx = 0; idx < nvers; idx++) { 2305*7697SMichael.Christensen@Sun.COM if (vers[idx].major > curr_major) { 2306*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has " 2307*7697SMichael.Christensen@Sun.COM " increasing major versions" DS_EOL); 2308*7697SMichael.Christensen@Sun.COM return (DS_VERS_INCREASING_MAJOR_ERR); 2309*7697SMichael.Christensen@Sun.COM } 2310*7697SMichael.Christensen@Sun.COM 2311*7697SMichael.Christensen@Sun.COM if (vers[idx].major < curr_major) { 2312*7697SMichael.Christensen@Sun.COM curr_major = vers[idx].major; 2313*7697SMichael.Christensen@Sun.COM curr_minor = vers[idx].minor; 2314*7697SMichael.Christensen@Sun.COM continue; 2315*7697SMichael.Christensen@Sun.COM } 2316*7697SMichael.Christensen@Sun.COM 2317*7697SMichael.Christensen@Sun.COM if (vers[idx].minor > curr_minor) { 2318*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has " 2319*7697SMichael.Christensen@Sun.COM " increasing minor versions" DS_EOL); 2320*7697SMichael.Christensen@Sun.COM return (DS_VERS_INCREASING_MINOR_ERR); 2321*7697SMichael.Christensen@Sun.COM } 2322*7697SMichael.Christensen@Sun.COM 2323*7697SMichael.Christensen@Sun.COM curr_minor = vers[idx].minor; 2324*7697SMichael.Christensen@Sun.COM } 2325*7697SMichael.Christensen@Sun.COM 2326*7697SMichael.Christensen@Sun.COM return (DS_VERS_OK); 2327*7697SMichael.Christensen@Sun.COM } 2328*7697SMichael.Christensen@Sun.COM 2329*7697SMichael.Christensen@Sun.COM /* 2330*7697SMichael.Christensen@Sun.COM * Extended user capability init. 2331*7697SMichael.Christensen@Sun.COM */ 2332*7697SMichael.Christensen@Sun.COM int 2333*7697SMichael.Christensen@Sun.COM ds_ucap_init(ds_capability_t *cap, ds_clnt_ops_t *ops, uint32_t flags, 2334*7697SMichael.Christensen@Sun.COM int instance, ds_svc_hdl_t *hdlp) 2335*7697SMichael.Christensen@Sun.COM { 2336*7697SMichael.Christensen@Sun.COM ds_vers_check_t status; 2337*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2338*7697SMichael.Christensen@Sun.COM int rv = 0; 2339*7697SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl, hdl; 2340*7697SMichael.Christensen@Sun.COM int is_loopback; 2341*7697SMichael.Christensen@Sun.COM int is_client; 2342*7697SMichael.Christensen@Sun.COM 2343*7697SMichael.Christensen@Sun.COM /* sanity check the args */ 2344*7697SMichael.Christensen@Sun.COM if ((cap == NULL) || (ops == NULL)) { 2345*7697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid arguments" DS_EOL, __func__); 2346*7697SMichael.Christensen@Sun.COM return (EINVAL); 2347*7697SMichael.Christensen@Sun.COM } 2348*7697SMichael.Christensen@Sun.COM 2349*7697SMichael.Christensen@Sun.COM /* sanity check the capability specifier */ 2350*7697SMichael.Christensen@Sun.COM if ((cap->svc_id == NULL) || (cap->vers == NULL) || (cap->nvers == 0)) { 2351*7697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid capability specifier" DS_EOL, 2352*7697SMichael.Christensen@Sun.COM __func__); 2353*7697SMichael.Christensen@Sun.COM return (EINVAL); 2354*7697SMichael.Christensen@Sun.COM } 2355*7697SMichael.Christensen@Sun.COM 2356*7697SMichael.Christensen@Sun.COM /* sanity check the version array */ 2357*7697SMichael.Christensen@Sun.COM if ((status = ds_vers_isvalid(cap->vers, cap->nvers)) != DS_VERS_OK) { 2358*7697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid capability version array " 2359*7697SMichael.Christensen@Sun.COM "for %s service: %s" DS_EOL, __func__, cap->svc_id, 2360*7697SMichael.Christensen@Sun.COM (status == DS_VERS_INCREASING_MAJOR_ERR) ? 2361*7697SMichael.Christensen@Sun.COM "increasing major versions" : 2362*7697SMichael.Christensen@Sun.COM "increasing minor versions"); 2363*7697SMichael.Christensen@Sun.COM return (EINVAL); 2364*7697SMichael.Christensen@Sun.COM } 2365*7697SMichael.Christensen@Sun.COM 2366*7697SMichael.Christensen@Sun.COM /* data and register callbacks are required */ 2367*7697SMichael.Christensen@Sun.COM if ((ops->ds_data_cb == NULL) || (ops->ds_reg_cb == NULL)) { 2368*7697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid ops specifier for %s service" 2369*7697SMichael.Christensen@Sun.COM DS_EOL, __func__, cap->svc_id); 2370*7697SMichael.Christensen@Sun.COM return (EINVAL); 2371*7697SMichael.Christensen@Sun.COM } 2372*7697SMichael.Christensen@Sun.COM 2373*7697SMichael.Christensen@Sun.COM flags &= DSSF_USERFLAGS; 2374*7697SMichael.Christensen@Sun.COM is_client = flags & DSSF_ISCLIENT; 2375*7697SMichael.Christensen@Sun.COM 2376*7697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: svc_id='%s', data_cb=0x%lx, cb_arg=0x%lx" 2377*7697SMichael.Christensen@Sun.COM DS_EOL, __func__, cap->svc_id, PTR_TO_LONG(ops->ds_data_cb), 2378*7697SMichael.Christensen@Sun.COM PTR_TO_LONG(ops->cb_arg)); 2379*7697SMichael.Christensen@Sun.COM 2380*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 2381*7697SMichael.Christensen@Sun.COM 2382*7697SMichael.Christensen@Sun.COM /* check if the service is already registered */ 2383*7697SMichael.Christensen@Sun.COM if (i_ds_hdl_lookup(cap->svc_id, is_client, NULL, 1) == 1) { 2384*7697SMichael.Christensen@Sun.COM /* already registered */ 2385*7697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "Service '%s'/%s already registered" DS_EOL, 2386*7697SMichael.Christensen@Sun.COM cap->svc_id, 2387*7697SMichael.Christensen@Sun.COM (flags & DSSF_ISCLIENT) ? "client" : "service"); 2388*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2389*7697SMichael.Christensen@Sun.COM return (EALREADY); 2390*7697SMichael.Christensen@Sun.COM } 2391*7697SMichael.Christensen@Sun.COM 2392*7697SMichael.Christensen@Sun.COM svc = ds_alloc_svc(); 2393*7697SMichael.Christensen@Sun.COM if (is_client) { 2394*7697SMichael.Christensen@Sun.COM DS_HDL_SET_ISCLIENT(svc->hdl); 2395*7697SMichael.Christensen@Sun.COM } 2396*7697SMichael.Christensen@Sun.COM 2397*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_FREE; 2398*7697SMichael.Christensen@Sun.COM svc->svc_hdl = DS_BADHDL1; 2399*7697SMichael.Christensen@Sun.COM 2400*7697SMichael.Christensen@Sun.COM svc->flags = flags; 2401*7697SMichael.Christensen@Sun.COM svc->drvi = instance; 2402*7697SMichael.Christensen@Sun.COM svc->drv_psp = NULL; 2403*7697SMichael.Christensen@Sun.COM 2404*7697SMichael.Christensen@Sun.COM /* 2405*7697SMichael.Christensen@Sun.COM * Check for loopback. 2406*7697SMichael.Christensen@Sun.COM */ 2407*7697SMichael.Christensen@Sun.COM if (i_ds_hdl_lookup(cap->svc_id, is_client == 0, &lb_hdl, 1) == 1) { 2408*7697SMichael.Christensen@Sun.COM if ((rv = ds_loopback_set_svc(svc, lb_hdl)) != 0) { 2409*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "%s: ds_loopback_set_svc err (%d)" 2410*7697SMichael.Christensen@Sun.COM DS_EOL, __func__, rv); 2411*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2412*7697SMichael.Christensen@Sun.COM return (rv); 2413*7697SMichael.Christensen@Sun.COM } 2414*7697SMichael.Christensen@Sun.COM is_loopback = 1; 2415*7697SMichael.Christensen@Sun.COM } else 2416*7697SMichael.Christensen@Sun.COM is_loopback = 0; 2417*7697SMichael.Christensen@Sun.COM 2418*7697SMichael.Christensen@Sun.COM /* copy over all the client information */ 2419*7697SMichael.Christensen@Sun.COM (void) memcpy(&svc->cap, cap, sizeof (ds_capability_t)); 2420*7697SMichael.Christensen@Sun.COM 2421*7697SMichael.Christensen@Sun.COM /* make a copy of the service name */ 2422*7697SMichael.Christensen@Sun.COM svc->cap.svc_id = ds_strdup(cap->svc_id); 2423*7697SMichael.Christensen@Sun.COM 2424*7697SMichael.Christensen@Sun.COM /* make a copy of the version array */ 2425*7697SMichael.Christensen@Sun.COM svc->cap.vers = DS_MALLOC(cap->nvers * sizeof (ds_ver_t)); 2426*7697SMichael.Christensen@Sun.COM (void) memcpy(svc->cap.vers, cap->vers, cap->nvers * sizeof (ds_ver_t)); 2427*7697SMichael.Christensen@Sun.COM 2428*7697SMichael.Christensen@Sun.COM /* copy the client ops vector */ 2429*7697SMichael.Christensen@Sun.COM (void) memcpy(&svc->ops, ops, sizeof (ds_clnt_ops_t)); 2430*7697SMichael.Christensen@Sun.COM 2431*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 2432*7697SMichael.Christensen@Sun.COM svc->ver_idx = 0; 2433*7697SMichael.Christensen@Sun.COM DS_PORTSET_DUP(svc->avail, ds_allports); 2434*7697SMichael.Christensen@Sun.COM DS_PORTSET_SETNULL(svc->tried); 2435*7697SMichael.Christensen@Sun.COM 2436*7697SMichael.Christensen@Sun.COM ds_svcs.nsvcs++; 2437*7697SMichael.Christensen@Sun.COM 2438*7697SMichael.Christensen@Sun.COM hdl = svc->hdl; 2439*7697SMichael.Christensen@Sun.COM 2440*7697SMichael.Christensen@Sun.COM /* 2441*7697SMichael.Christensen@Sun.COM * kludge to allow user callback code to get handle and user args. 2442*7697SMichael.Christensen@Sun.COM * Make sure the callback arg points to the svc structure. 2443*7697SMichael.Christensen@Sun.COM */ 2444*7697SMichael.Christensen@Sun.COM if ((flags & DSSF_ISUSER) != 0) { 2445*7697SMichael.Christensen@Sun.COM ds_cbarg_set_cookie(svc); 2446*7697SMichael.Christensen@Sun.COM } 2447*7697SMichael.Christensen@Sun.COM 2448*7697SMichael.Christensen@Sun.COM if (is_loopback) { 2449*7697SMichael.Christensen@Sun.COM ds_loopback_register(hdl); 2450*7697SMichael.Christensen@Sun.COM ds_loopback_register(lb_hdl); 2451*7697SMichael.Christensen@Sun.COM } 2452*7697SMichael.Christensen@Sun.COM 2453*7697SMichael.Christensen@Sun.COM /* 2454*7697SMichael.Christensen@Sun.COM * If this is a client or a non-loopback service provider, send 2455*7697SMichael.Christensen@Sun.COM * out register requests. 2456*7697SMichael.Christensen@Sun.COM */ 2457*7697SMichael.Christensen@Sun.COM if (!is_loopback || (flags & DSSF_ISCLIENT) != 0) 2458*7697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 2459*7697SMichael.Christensen@Sun.COM 2460*7697SMichael.Christensen@Sun.COM if (hdlp) { 2461*7697SMichael.Christensen@Sun.COM *hdlp = hdl; 2462*7697SMichael.Christensen@Sun.COM } 2463*7697SMichael.Christensen@Sun.COM 2464*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2465*7697SMichael.Christensen@Sun.COM 2466*7697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: service '%s' assigned handle 0x%09lx" DS_EOL, 2467*7697SMichael.Christensen@Sun.COM __func__, svc->cap.svc_id, hdl); 2468*7697SMichael.Christensen@Sun.COM 2469*7697SMichael.Christensen@Sun.COM return (0); 2470*7697SMichael.Christensen@Sun.COM } 2471*7697SMichael.Christensen@Sun.COM 2472*7697SMichael.Christensen@Sun.COM /* 2473*7697SMichael.Christensen@Sun.COM * ds_cap_init interface for previous revision. 2474*7697SMichael.Christensen@Sun.COM */ 2475*7697SMichael.Christensen@Sun.COM int 2476*7697SMichael.Christensen@Sun.COM ds_cap_init(ds_capability_t *cap, ds_clnt_ops_t *ops) 2477*7697SMichael.Christensen@Sun.COM { 2478*7697SMichael.Christensen@Sun.COM return (ds_ucap_init(cap, ops, 0, DS_INVALID_INSTANCE, NULL)); 2479*7697SMichael.Christensen@Sun.COM } 2480*7697SMichael.Christensen@Sun.COM 2481*7697SMichael.Christensen@Sun.COM /* 2482*7697SMichael.Christensen@Sun.COM * Interface for ds_unreg_hdl in lds driver. 2483*7697SMichael.Christensen@Sun.COM */ 2484*7697SMichael.Christensen@Sun.COM int 2485*7697SMichael.Christensen@Sun.COM ds_unreg_hdl(ds_svc_hdl_t hdl) 2486*7697SMichael.Christensen@Sun.COM { 2487*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2488*7697SMichael.Christensen@Sun.COM int is_loopback; 2489*7697SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl; 2490*7697SMichael.Christensen@Sun.COM 2491*7697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: hdl=0x%09lx" DS_EOL, __func__, hdl); 2492*7697SMichael.Christensen@Sun.COM 2493*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 2494*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 2495*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2496*7697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: unknown hdl: 0x%llx" DS_EOL, __func__, 2497*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2498*7697SMichael.Christensen@Sun.COM return (ENXIO); 2499*7697SMichael.Christensen@Sun.COM } 2500*7697SMichael.Christensen@Sun.COM 2501*7697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: svcid='%s', hdl=0x%llx" DS_EOL, __func__, 2502*7697SMichael.Christensen@Sun.COM svc->cap.svc_id, (u_longlong_t)svc->hdl); 2503*7697SMichael.Christensen@Sun.COM 2504*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_UNREG_PENDING; 2505*7697SMichael.Christensen@Sun.COM 2506*7697SMichael.Christensen@Sun.COM is_loopback = ((svc->flags & DSSF_LOOPBACK) != 0); 2507*7697SMichael.Christensen@Sun.COM lb_hdl = svc->svc_hdl; 2508*7697SMichael.Christensen@Sun.COM 2509*7697SMichael.Christensen@Sun.COM if (svc->port) { 2510*7697SMichael.Christensen@Sun.COM (void) ds_send_unreg_req(svc); 2511*7697SMichael.Christensen@Sun.COM } 2512*7697SMichael.Christensen@Sun.COM 2513*7697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 2514*7697SMichael.Christensen@Sun.COM 2515*7697SMichael.Christensen@Sun.COM ds_delete_svc_entry(svc); 2516*7697SMichael.Christensen@Sun.COM 2517*7697SMichael.Christensen@Sun.COM if (is_loopback) { 2518*7697SMichael.Christensen@Sun.COM ds_loopback_unregister(lb_hdl); 2519*7697SMichael.Christensen@Sun.COM } 2520*7697SMichael.Christensen@Sun.COM 2521*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2522*7697SMichael.Christensen@Sun.COM 2523*7697SMichael.Christensen@Sun.COM return (0); 2524*7697SMichael.Christensen@Sun.COM } 2525*7697SMichael.Christensen@Sun.COM 2526*7697SMichael.Christensen@Sun.COM int 2527*7697SMichael.Christensen@Sun.COM ds_cap_fini(ds_capability_t *cap) 2528*7697SMichael.Christensen@Sun.COM { 2529*7697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 2530*7697SMichael.Christensen@Sun.COM int rv; 2531*7697SMichael.Christensen@Sun.COM uint_t nhdls = 0; 2532*7697SMichael.Christensen@Sun.COM 2533*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: '%s'" DS_EOL, __func__, cap->svc_id); 2534*7697SMichael.Christensen@Sun.COM if ((rv = ds_hdl_lookup(cap->svc_id, 0, &hdl, 1, &nhdls)) != 0) { 2535*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_hdl_lookup '%s' err (%d)" DS_EOL, 2536*7697SMichael.Christensen@Sun.COM __func__, cap->svc_id, rv); 2537*7697SMichael.Christensen@Sun.COM return (rv); 2538*7697SMichael.Christensen@Sun.COM } 2539*7697SMichael.Christensen@Sun.COM 2540*7697SMichael.Christensen@Sun.COM if (nhdls == 0) { 2541*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: no such service '%s'" DS_EOL, 2542*7697SMichael.Christensen@Sun.COM __func__, cap->svc_id); 2543*7697SMichael.Christensen@Sun.COM return (ENXIO); 2544*7697SMichael.Christensen@Sun.COM } 2545*7697SMichael.Christensen@Sun.COM 2546*7697SMichael.Christensen@Sun.COM if ((rv = ds_is_my_hdl(hdl, DS_INVALID_INSTANCE)) != 0) { 2547*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_is_my_handle err (%d)" DS_EOL, __func__, 2548*7697SMichael.Christensen@Sun.COM rv); 2549*7697SMichael.Christensen@Sun.COM return (rv); 2550*7697SMichael.Christensen@Sun.COM } 2551*7697SMichael.Christensen@Sun.COM 2552*7697SMichael.Christensen@Sun.COM if ((rv = ds_unreg_hdl(hdl)) != 0) { 2553*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_unreg_hdl err (%d)" DS_EOL, __func__, 2554*7697SMichael.Christensen@Sun.COM rv); 2555*7697SMichael.Christensen@Sun.COM return (rv); 2556*7697SMichael.Christensen@Sun.COM } 2557*7697SMichael.Christensen@Sun.COM 2558*7697SMichael.Christensen@Sun.COM return (0); 2559*7697SMichael.Christensen@Sun.COM } 2560*7697SMichael.Christensen@Sun.COM 2561*7697SMichael.Christensen@Sun.COM int 2562*7697SMichael.Christensen@Sun.COM ds_cap_send(ds_svc_hdl_t hdl, void *buf, size_t len) 2563*7697SMichael.Christensen@Sun.COM { 2564*7697SMichael.Christensen@Sun.COM int rv; 2565*7697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 2566*7697SMichael.Christensen@Sun.COM caddr_t msg; 2567*7697SMichael.Christensen@Sun.COM size_t msglen; 2568*7697SMichael.Christensen@Sun.COM size_t hdrlen; 2569*7697SMichael.Christensen@Sun.COM caddr_t payload; 2570*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2571*7697SMichael.Christensen@Sun.COM ds_port_t *port; 2572*7697SMichael.Christensen@Sun.COM ds_data_handle_t *data; 2573*7697SMichael.Christensen@Sun.COM ds_svc_hdl_t svc_hdl; 2574*7697SMichael.Christensen@Sun.COM int is_client = 0; 2575*7697SMichael.Christensen@Sun.COM 2576*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: hdl: 0x%llx, buf: %lx, len: %ld" DS_EOL, __func__, 2577*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl, (ulong_t)buf, len); 2578*7697SMichael.Christensen@Sun.COM 2579*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 2580*7697SMichael.Christensen@Sun.COM 2581*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 2582*7697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "%s: invalid handle 0x%llx" DS_EOL, __func__, 2583*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2584*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2585*7697SMichael.Christensen@Sun.COM return (ENXIO); 2586*7697SMichael.Christensen@Sun.COM } 2587*7697SMichael.Christensen@Sun.COM 2588*7697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_ACTIVE) { 2589*7697SMichael.Christensen@Sun.COM /* channel is up, but svc is not registered */ 2590*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: invalid service state 0x%x" DS_EOL, 2591*7697SMichael.Christensen@Sun.COM __func__, svc->state); 2592*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2593*7697SMichael.Christensen@Sun.COM return (ENOTCONN); 2594*7697SMichael.Christensen@Sun.COM } 2595*7697SMichael.Christensen@Sun.COM 2596*7697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_LOOPBACK) { 2597*7697SMichael.Christensen@Sun.COM hdl = svc->svc_hdl; 2598*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2599*7697SMichael.Christensen@Sun.COM ds_loopback_send(hdl, buf, len); 2600*7697SMichael.Christensen@Sun.COM return (0); 2601*7697SMichael.Christensen@Sun.COM } 2602*7697SMichael.Christensen@Sun.COM 2603*7697SMichael.Christensen@Sun.COM if ((port = svc->port) == NULL) { 2604*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: service '%s' not associated with a port" 2605*7697SMichael.Christensen@Sun.COM DS_EOL, __func__, svc->cap.svc_id); 2606*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2607*7697SMichael.Christensen@Sun.COM return (ECONNRESET); 2608*7697SMichael.Christensen@Sun.COM } 2609*7697SMichael.Christensen@Sun.COM 2610*7697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 2611*7697SMichael.Christensen@Sun.COM is_client = 1; 2612*7697SMichael.Christensen@Sun.COM svc_hdl = svc->svc_hdl; 2613*7697SMichael.Christensen@Sun.COM } 2614*7697SMichael.Christensen@Sun.COM 2615*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2616*7697SMichael.Christensen@Sun.COM 2617*7697SMichael.Christensen@Sun.COM /* check that the LDC channel is ready */ 2618*7697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 2619*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: LDC channel is not up" DS_EOL, __func__); 2620*7697SMichael.Christensen@Sun.COM return (ECONNRESET); 2621*7697SMichael.Christensen@Sun.COM } 2622*7697SMichael.Christensen@Sun.COM 2623*7697SMichael.Christensen@Sun.COM hdrlen = DS_HDR_SZ + sizeof (ds_data_handle_t); 2624*7697SMichael.Christensen@Sun.COM 2625*7697SMichael.Christensen@Sun.COM msg = DS_MALLOC(len + hdrlen); 2626*7697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 2627*7697SMichael.Christensen@Sun.COM payload = msg + hdrlen; 2628*7697SMichael.Christensen@Sun.COM msglen = len + hdrlen; 2629*7697SMichael.Christensen@Sun.COM 2630*7697SMichael.Christensen@Sun.COM hdr->payload_len = len + sizeof (ds_data_handle_t); 2631*7697SMichael.Christensen@Sun.COM hdr->msg_type = DS_DATA; 2632*7697SMichael.Christensen@Sun.COM 2633*7697SMichael.Christensen@Sun.COM data = (ds_data_handle_t *)(msg + DS_HDR_SZ); 2634*7697SMichael.Christensen@Sun.COM if (is_client) { 2635*7697SMichael.Christensen@Sun.COM data->svc_handle = svc_hdl; 2636*7697SMichael.Christensen@Sun.COM } else { 2637*7697SMichael.Christensen@Sun.COM data->svc_handle = hdl; 2638*7697SMichael.Christensen@Sun.COM } 2639*7697SMichael.Christensen@Sun.COM 2640*7697SMichael.Christensen@Sun.COM if ((buf != NULL) && (len != 0)) { 2641*7697SMichael.Christensen@Sun.COM (void) memcpy(payload, buf, len); 2642*7697SMichael.Christensen@Sun.COM } 2643*7697SMichael.Christensen@Sun.COM 2644*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data>: hdl=0x%llx, len=%ld, " 2645*7697SMichael.Christensen@Sun.COM " payload_len=%d" DS_EOL, PORTID(port), (u_longlong_t)svc->hdl, 2646*7697SMichael.Christensen@Sun.COM msglen, hdr->payload_len); 2647*7697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msglen); 2648*7697SMichael.Christensen@Sun.COM 2649*7697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 2650*7697SMichael.Christensen@Sun.COM rv = (rv == EIO) ? ECONNRESET : rv; 2651*7697SMichael.Christensen@Sun.COM } 2652*7697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 2653*7697SMichael.Christensen@Sun.COM 2654*7697SMichael.Christensen@Sun.COM return (rv); 2655*7697SMichael.Christensen@Sun.COM } 2656*7697SMichael.Christensen@Sun.COM 2657*7697SMichael.Christensen@Sun.COM void 2658*7697SMichael.Christensen@Sun.COM ds_port_common_init(ds_port_t *port) 2659*7697SMichael.Christensen@Sun.COM { 2660*7697SMichael.Christensen@Sun.COM int rv; 2661*7697SMichael.Christensen@Sun.COM 2662*7697SMichael.Christensen@Sun.COM if ((port->flags & DS_PORT_MUTEX_INITED) == 0) { 2663*7697SMichael.Christensen@Sun.COM mutex_init(&port->lock, NULL, MUTEX_DRIVER, NULL); 2664*7697SMichael.Christensen@Sun.COM mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL); 2665*7697SMichael.Christensen@Sun.COM mutex_init(&port->rcv_lock, NULL, MUTEX_DRIVER, NULL); 2666*7697SMichael.Christensen@Sun.COM port->flags |= DS_PORT_MUTEX_INITED; 2667*7697SMichael.Christensen@Sun.COM } 2668*7697SMichael.Christensen@Sun.COM 2669*7697SMichael.Christensen@Sun.COM port->state = DS_PORT_INIT; 2670*7697SMichael.Christensen@Sun.COM DS_PORTSET_ADD(ds_allports, port->id); 2671*7697SMichael.Christensen@Sun.COM 2672*7697SMichael.Christensen@Sun.COM ds_sys_port_init(port); 2673*7697SMichael.Christensen@Sun.COM 2674*7697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 2675*7697SMichael.Christensen@Sun.COM rv = ds_ldc_init(port); 2676*7697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 2677*7697SMichael.Christensen@Sun.COM 2678*7697SMichael.Christensen@Sun.COM /* 2679*7697SMichael.Christensen@Sun.COM * If LDC successfully init'ed, try to kick off protocol for this port. 2680*7697SMichael.Christensen@Sun.COM */ 2681*7697SMichael.Christensen@Sun.COM if (rv == 0) { 2682*7697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 2683*7697SMichael.Christensen@Sun.COM } 2684*7697SMichael.Christensen@Sun.COM } 2685*7697SMichael.Christensen@Sun.COM 2686*7697SMichael.Christensen@Sun.COM void 2687*7697SMichael.Christensen@Sun.COM ds_port_common_fini(ds_port_t *port, int is_fini) 2688*7697SMichael.Christensen@Sun.COM { 2689*7697SMichael.Christensen@Sun.COM port->state = DS_PORT_FREE; 2690*7697SMichael.Christensen@Sun.COM 2691*7697SMichael.Christensen@Sun.COM if (is_fini && (port->flags & DS_PORT_MUTEX_INITED) != 0) { 2692*7697SMichael.Christensen@Sun.COM mutex_destroy(&port->lock); 2693*7697SMichael.Christensen@Sun.COM mutex_destroy(&port->tx_lock); 2694*7697SMichael.Christensen@Sun.COM mutex_destroy(&port->rcv_lock); 2695*7697SMichael.Christensen@Sun.COM port->flags &= ~DS_PORT_MUTEX_INITED; 2696*7697SMichael.Christensen@Sun.COM } 2697*7697SMichael.Christensen@Sun.COM 2698*7697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(ds_allports, port->id); 2699*7697SMichael.Christensen@Sun.COM 2700*7697SMichael.Christensen@Sun.COM ds_sys_port_fini(port); 2701*7697SMichael.Christensen@Sun.COM } 2702*7697SMichael.Christensen@Sun.COM 2703*7697SMichael.Christensen@Sun.COM /* 2704*7697SMichael.Christensen@Sun.COM * Initialize table of registered service classes 2705*7697SMichael.Christensen@Sun.COM */ 2706*7697SMichael.Christensen@Sun.COM void 2707*7697SMichael.Christensen@Sun.COM ds_init_svcs_tbl(uint_t nentries) 2708*7697SMichael.Christensen@Sun.COM { 2709*7697SMichael.Christensen@Sun.COM int tblsz; 2710*7697SMichael.Christensen@Sun.COM 2711*7697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs = nentries; 2712*7697SMichael.Christensen@Sun.COM 2713*7697SMichael.Christensen@Sun.COM tblsz = ds_svcs.maxsvcs * sizeof (ds_svc_t *); 2714*7697SMichael.Christensen@Sun.COM ds_svcs.tbl = (ds_svc_t **)DS_MALLOC(tblsz); 2715*7697SMichael.Christensen@Sun.COM 2716*7697SMichael.Christensen@Sun.COM ds_svcs.nsvcs = 0; 2717*7697SMichael.Christensen@Sun.COM } 2718*7697SMichael.Christensen@Sun.COM 2719*7697SMichael.Christensen@Sun.COM /* 2720*7697SMichael.Christensen@Sun.COM * Find the max and min version supported. 2721*7697SMichael.Christensen@Sun.COM * Hacked from zeus workspace, support.c 2722*7697SMichael.Christensen@Sun.COM */ 2723*7697SMichael.Christensen@Sun.COM static void 2724*7697SMichael.Christensen@Sun.COM min_max_versions(int num_versions, ds_ver_t *sup_versionsp, 2725*7697SMichael.Christensen@Sun.COM uint16_t *min_major, uint16_t *max_major) 2726*7697SMichael.Christensen@Sun.COM { 2727*7697SMichael.Christensen@Sun.COM int i; 2728*7697SMichael.Christensen@Sun.COM 2729*7697SMichael.Christensen@Sun.COM *min_major = sup_versionsp[0].major; 2730*7697SMichael.Christensen@Sun.COM *max_major = *min_major; 2731*7697SMichael.Christensen@Sun.COM 2732*7697SMichael.Christensen@Sun.COM for (i = 1; i < num_versions; i++) { 2733*7697SMichael.Christensen@Sun.COM if (sup_versionsp[i].major < *min_major) 2734*7697SMichael.Christensen@Sun.COM *min_major = sup_versionsp[i].major; 2735*7697SMichael.Christensen@Sun.COM 2736*7697SMichael.Christensen@Sun.COM if (sup_versionsp[i].major > *max_major) 2737*7697SMichael.Christensen@Sun.COM *max_major = sup_versionsp[i].major; 2738*7697SMichael.Christensen@Sun.COM } 2739*7697SMichael.Christensen@Sun.COM } 2740*7697SMichael.Christensen@Sun.COM 2741*7697SMichael.Christensen@Sun.COM /* 2742*7697SMichael.Christensen@Sun.COM * Check whether the major and minor numbers requested by the peer can be 2743*7697SMichael.Christensen@Sun.COM * satisfied. If the requested major is supported, true is returned, and the 2744*7697SMichael.Christensen@Sun.COM * agreed minor is returned in new_minor. If the requested major is not 2745*7697SMichael.Christensen@Sun.COM * supported, the routine returns false, and the closest major is returned in 2746*7697SMichael.Christensen@Sun.COM * *new_major, upon which the peer should re-negotiate. The closest major is 2747*7697SMichael.Christensen@Sun.COM * the just lower that the requested major number. 2748*7697SMichael.Christensen@Sun.COM * 2749*7697SMichael.Christensen@Sun.COM * Hacked from zeus workspace, support.c 2750*7697SMichael.Christensen@Sun.COM */ 2751*7697SMichael.Christensen@Sun.COM boolean_t 2752*7697SMichael.Christensen@Sun.COM negotiate_version(int num_versions, ds_ver_t *sup_versionsp, 2753*7697SMichael.Christensen@Sun.COM uint16_t req_major, uint16_t *new_majorp, uint16_t *new_minorp) 2754*7697SMichael.Christensen@Sun.COM { 2755*7697SMichael.Christensen@Sun.COM int i; 2756*7697SMichael.Christensen@Sun.COM uint16_t major, lower_major; 2757*7697SMichael.Christensen@Sun.COM uint16_t min_major = 0, max_major; 2758*7697SMichael.Christensen@Sun.COM boolean_t found_match = B_FALSE; 2759*7697SMichael.Christensen@Sun.COM 2760*7697SMichael.Christensen@Sun.COM min_max_versions(num_versions, sup_versionsp, &min_major, &max_major); 2761*7697SMichael.Christensen@Sun.COM 2762*7697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "negotiate_version: req_major = %u, min = %u, max = %u" 2763*7697SMichael.Christensen@Sun.COM DS_EOL, req_major, min_major, max_major); 2764*7697SMichael.Christensen@Sun.COM 2765*7697SMichael.Christensen@Sun.COM /* 2766*7697SMichael.Christensen@Sun.COM * If the minimum version supported is greater than 2767*7697SMichael.Christensen@Sun.COM * the version requested, return the lowest version 2768*7697SMichael.Christensen@Sun.COM * supported 2769*7697SMichael.Christensen@Sun.COM */ 2770*7697SMichael.Christensen@Sun.COM if (min_major > req_major) { 2771*7697SMichael.Christensen@Sun.COM *new_majorp = min_major; 2772*7697SMichael.Christensen@Sun.COM return (B_FALSE); 2773*7697SMichael.Christensen@Sun.COM } 2774*7697SMichael.Christensen@Sun.COM 2775*7697SMichael.Christensen@Sun.COM /* 2776*7697SMichael.Christensen@Sun.COM * If the largest version supported is lower than 2777*7697SMichael.Christensen@Sun.COM * the version requested, return the largest version 2778*7697SMichael.Christensen@Sun.COM * supported 2779*7697SMichael.Christensen@Sun.COM */ 2780*7697SMichael.Christensen@Sun.COM if (max_major < req_major) { 2781*7697SMichael.Christensen@Sun.COM *new_majorp = max_major; 2782*7697SMichael.Christensen@Sun.COM return (B_FALSE); 2783*7697SMichael.Christensen@Sun.COM } 2784*7697SMichael.Christensen@Sun.COM 2785*7697SMichael.Christensen@Sun.COM /* 2786*7697SMichael.Christensen@Sun.COM * Now we know that the requested version lies between the 2787*7697SMichael.Christensen@Sun.COM * min and max versions supported. Check if the requested 2788*7697SMichael.Christensen@Sun.COM * major can be found in supported versions. 2789*7697SMichael.Christensen@Sun.COM */ 2790*7697SMichael.Christensen@Sun.COM lower_major = min_major; 2791*7697SMichael.Christensen@Sun.COM for (i = 0; i < num_versions; i++) { 2792*7697SMichael.Christensen@Sun.COM major = sup_versionsp[i].major; 2793*7697SMichael.Christensen@Sun.COM if (major == req_major) { 2794*7697SMichael.Christensen@Sun.COM found_match = B_TRUE; 2795*7697SMichael.Christensen@Sun.COM *new_majorp = req_major; 2796*7697SMichael.Christensen@Sun.COM *new_minorp = sup_versionsp[i].minor; 2797*7697SMichael.Christensen@Sun.COM break; 2798*7697SMichael.Christensen@Sun.COM } else { 2799*7697SMichael.Christensen@Sun.COM if ((major < req_major) && (major > lower_major)) 2800*7697SMichael.Christensen@Sun.COM lower_major = major; 2801*7697SMichael.Christensen@Sun.COM } 2802*7697SMichael.Christensen@Sun.COM } 2803*7697SMichael.Christensen@Sun.COM 2804*7697SMichael.Christensen@Sun.COM /* 2805*7697SMichael.Christensen@Sun.COM * If no match is found, return the closest available number 2806*7697SMichael.Christensen@Sun.COM */ 2807*7697SMichael.Christensen@Sun.COM if (!found_match) 2808*7697SMichael.Christensen@Sun.COM *new_majorp = lower_major; 2809*7697SMichael.Christensen@Sun.COM 2810*7697SMichael.Christensen@Sun.COM return (found_match); 2811*7697SMichael.Christensen@Sun.COM } 2812*7697SMichael.Christensen@Sun.COM 2813*7697SMichael.Christensen@Sun.COM /* 2814*7697SMichael.Christensen@Sun.COM * Specific errno's that are used by ds.c and ldc.c 2815*7697SMichael.Christensen@Sun.COM */ 2816*7697SMichael.Christensen@Sun.COM static struct { 2817*7697SMichael.Christensen@Sun.COM int ds_errno; 2818*7697SMichael.Christensen@Sun.COM char *estr; 2819*7697SMichael.Christensen@Sun.COM } ds_errno_to_str_tab[] = { 2820*7697SMichael.Christensen@Sun.COM { EIO, "I/O error" }, 2821*7697SMichael.Christensen@Sun.COM { ENXIO, "No such device or address" }, 2822*7697SMichael.Christensen@Sun.COM { EAGAIN, "Resource temporarily unavailable" }, 2823*7697SMichael.Christensen@Sun.COM { ENOMEM, "Not enough space" }, 2824*7697SMichael.Christensen@Sun.COM { EACCES, "Permission denied" }, 2825*7697SMichael.Christensen@Sun.COM { EFAULT, "Bad address" }, 2826*7697SMichael.Christensen@Sun.COM { EBUSY, "Device busy" }, 2827*7697SMichael.Christensen@Sun.COM { EINVAL, "Invalid argument" }, 2828*7697SMichael.Christensen@Sun.COM { ENOSPC, "No space left on device" }, 2829*7697SMichael.Christensen@Sun.COM { ENOMSG, "No message of desired type" }, 2830*7697SMichael.Christensen@Sun.COM #ifdef ECHRNG 2831*7697SMichael.Christensen@Sun.COM { ECHRNG, "Channel number out of range" }, 2832*7697SMichael.Christensen@Sun.COM #endif 2833*7697SMichael.Christensen@Sun.COM { ENOTSUP, "Operation not supported" }, 2834*7697SMichael.Christensen@Sun.COM { EMSGSIZE, "Message too long" }, 2835*7697SMichael.Christensen@Sun.COM { EADDRINUSE, "Address already in use" }, 2836*7697SMichael.Christensen@Sun.COM { ECONNRESET, "Connection reset by peer" }, 2837*7697SMichael.Christensen@Sun.COM { ENOBUFS, "No buffer space available" }, 2838*7697SMichael.Christensen@Sun.COM { ENOTCONN, "Socket is not connected" }, 2839*7697SMichael.Christensen@Sun.COM { ECONNREFUSED, "Connection refused" }, 2840*7697SMichael.Christensen@Sun.COM { EALREADY, "Operation already in progress" }, 2841*7697SMichael.Christensen@Sun.COM { 0, NULL }, 2842*7697SMichael.Christensen@Sun.COM }; 2843*7697SMichael.Christensen@Sun.COM 2844*7697SMichael.Christensen@Sun.COM char * 2845*7697SMichael.Christensen@Sun.COM ds_errno_to_str(int ds_errno, char *ebuf) 2846*7697SMichael.Christensen@Sun.COM { 2847*7697SMichael.Christensen@Sun.COM int i, en; 2848*7697SMichael.Christensen@Sun.COM 2849*7697SMichael.Christensen@Sun.COM for (i = 0; (en = ds_errno_to_str_tab[i].ds_errno) != 0; i++) { 2850*7697SMichael.Christensen@Sun.COM if (en == ds_errno) { 2851*7697SMichael.Christensen@Sun.COM (void) strcpy(ebuf, ds_errno_to_str_tab[i].estr); 2852*7697SMichael.Christensen@Sun.COM return (ebuf); 2853*7697SMichael.Christensen@Sun.COM } 2854*7697SMichael.Christensen@Sun.COM } 2855*7697SMichael.Christensen@Sun.COM 2856*7697SMichael.Christensen@Sun.COM (void) sprintf(ebuf, "ds_errno (%d)", ds_errno); 2857*7697SMichael.Christensen@Sun.COM return (ebuf); 2858*7697SMichael.Christensen@Sun.COM } 2859*7697SMichael.Christensen@Sun.COM 2860*7697SMichael.Christensen@Sun.COM static void 2861*7697SMichael.Christensen@Sun.COM ds_loopback_register(ds_svc_hdl_t hdl) 2862*7697SMichael.Christensen@Sun.COM { 2863*7697SMichael.Christensen@Sun.COM ds_ver_t ds_ver = { 1, 0}; 2864*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2865*7697SMichael.Christensen@Sun.COM 2866*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2867*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 2868*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2869*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 2870*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 2871*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2872*7697SMichael.Christensen@Sun.COM return; 2873*7697SMichael.Christensen@Sun.COM } 2874*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 2875*7697SMichael.Christensen@Sun.COM 2876*7697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 2877*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback regcb: hdl: 0x%llx" DS_EOL, 2878*7697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 2879*7697SMichael.Christensen@Sun.COM ds_ver.major = svc->ver.major; 2880*7697SMichael.Christensen@Sun.COM ds_ver.minor = svc->ver.minor; 2881*7697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &ds_ver, hdl); 2882*7697SMichael.Christensen@Sun.COM } 2883*7697SMichael.Christensen@Sun.COM } 2884*7697SMichael.Christensen@Sun.COM 2885*7697SMichael.Christensen@Sun.COM static void 2886*7697SMichael.Christensen@Sun.COM ds_loopback_unregister(ds_svc_hdl_t hdl) 2887*7697SMichael.Christensen@Sun.COM { 2888*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2889*7697SMichael.Christensen@Sun.COM 2890*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2891*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 2892*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 2893*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2894*7697SMichael.Christensen@Sun.COM return; 2895*7697SMichael.Christensen@Sun.COM } 2896*7697SMichael.Christensen@Sun.COM 2897*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 2898*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2899*7697SMichael.Christensen@Sun.COM 2900*7697SMichael.Christensen@Sun.COM svc->flags &= ~DSSF_LOOPBACK; 2901*7697SMichael.Christensen@Sun.COM svc->svc_hdl = DS_BADHDL2; 2902*7697SMichael.Christensen@Sun.COM 2903*7697SMichael.Christensen@Sun.COM if (svc->ops.ds_unreg_cb) { 2904*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback unregcb: hdl: 0x%llx" DS_EOL, 2905*7697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 2906*7697SMichael.Christensen@Sun.COM (*svc->ops.ds_unreg_cb)(svc->ops.cb_arg); 2907*7697SMichael.Christensen@Sun.COM } 2908*7697SMichael.Christensen@Sun.COM } 2909*7697SMichael.Christensen@Sun.COM 2910*7697SMichael.Christensen@Sun.COM static void 2911*7697SMichael.Christensen@Sun.COM ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen) 2912*7697SMichael.Christensen@Sun.COM { 2913*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2914*7697SMichael.Christensen@Sun.COM 2915*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 2916*7697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 2917*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2918*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 2919*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2920*7697SMichael.Christensen@Sun.COM return; 2921*7697SMichael.Christensen@Sun.COM } 2922*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2923*7697SMichael.Christensen@Sun.COM 2924*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 2925*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 2926*7697SMichael.Christensen@Sun.COM 2927*7697SMichael.Christensen@Sun.COM if (svc->ops.ds_data_cb) { 2928*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback datacb hdl: 0x%llx" DS_EOL, 2929*7697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 2930*7697SMichael.Christensen@Sun.COM (*svc->ops.ds_data_cb)(svc->ops.cb_arg, buf, buflen); 2931*7697SMichael.Christensen@Sun.COM } 2932*7697SMichael.Christensen@Sun.COM } 2933*7697SMichael.Christensen@Sun.COM 2934*7697SMichael.Christensen@Sun.COM static int 2935*7697SMichael.Christensen@Sun.COM ds_loopback_set_svc(ds_svc_t *svc, ds_svc_hdl_t lb_hdl) 2936*7697SMichael.Christensen@Sun.COM { 2937*7697SMichael.Christensen@Sun.COM ds_svc_t *lb_svc; 2938*7697SMichael.Christensen@Sun.COM 2939*7697SMichael.Christensen@Sun.COM if ((lb_svc = ds_get_svc(lb_hdl)) == NULL) { 2940*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback: hdl: 0x%llx invalid" DS_EOL, 2941*7697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)lb_hdl); 2942*7697SMichael.Christensen@Sun.COM return (ENXIO); 2943*7697SMichael.Christensen@Sun.COM } 2944*7697SMichael.Christensen@Sun.COM if (lb_svc->state != DS_SVC_INACTIVE) { 2945*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback inactive: hdl: 0x%llx" 2946*7697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)lb_hdl); 2947*7697SMichael.Christensen@Sun.COM if ((lb_svc->flags & DSSF_ISCLIENT) == 0) { 2948*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback busy hdl: 0x%llx" 2949*7697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)lb_hdl); 2950*7697SMichael.Christensen@Sun.COM return (EBUSY); 2951*7697SMichael.Christensen@Sun.COM } 2952*7697SMichael.Christensen@Sun.COM lb_svc = ds_svc_clone(lb_svc); 2953*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback clone: ohdl: 0x%llx " 2954*7697SMichael.Christensen@Sun.COM "nhdl: 0x%llx" DS_EOL, __func__, (u_longlong_t)lb_hdl, 2955*7697SMichael.Christensen@Sun.COM (u_longlong_t)lb_svc->hdl); 2956*7697SMichael.Christensen@Sun.COM } 2957*7697SMichael.Christensen@Sun.COM 2958*7697SMichael.Christensen@Sun.COM svc->flags |= DSSF_LOOPBACK; 2959*7697SMichael.Christensen@Sun.COM svc->svc_hdl = lb_svc->hdl; 2960*7697SMichael.Christensen@Sun.COM svc->port = NULL; 2961*7697SMichael.Christensen@Sun.COM 2962*7697SMichael.Christensen@Sun.COM lb_svc->flags |= DSSF_LOOPBACK; 2963*7697SMichael.Christensen@Sun.COM lb_svc->svc_hdl = svc->hdl; 2964*7697SMichael.Christensen@Sun.COM lb_svc->port = NULL; 2965*7697SMichael.Christensen@Sun.COM 2966*7697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: setting loopback between: 0x%llx and 0x%llx" 2967*7697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)svc->hdl, 2968*7697SMichael.Christensen@Sun.COM (u_longlong_t)lb_svc->hdl); 2969*7697SMichael.Christensen@Sun.COM return (0); 2970*7697SMichael.Christensen@Sun.COM } 2971*7697SMichael.Christensen@Sun.COM 2972*7697SMichael.Christensen@Sun.COM static ds_svc_t * 2973*7697SMichael.Christensen@Sun.COM ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl, ds_port_t *port) 2974*7697SMichael.Christensen@Sun.COM { 2975*7697SMichael.Christensen@Sun.COM int idx; 2976*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 2977*7697SMichael.Christensen@Sun.COM 2978*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s looking up clnt hdl: 0x%llx" DS_EOL, 2979*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)hdl); 2980*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2981*7697SMichael.Christensen@Sun.COM 2982*7697SMichael.Christensen@Sun.COM /* walk every table entry */ 2983*7697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 2984*7697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 2985*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 2986*7697SMichael.Christensen@Sun.COM continue; 2987*7697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != 0 && 2988*7697SMichael.Christensen@Sun.COM svc->svc_hdl == hdl && svc->port == port) { 2989*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s found clnt hdl " 2990*7697SMichael.Christensen@Sun.COM "0x%llx: svc%d" DS_EOL, PORTID(port), __func__, 2991*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl, (uint_t)DS_HDL2IDX(svc->hdl)); 2992*7697SMichael.Christensen@Sun.COM return (svc); 2993*7697SMichael.Christensen@Sun.COM } 2994*7697SMichael.Christensen@Sun.COM } 2995*7697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s clnt hdl: 0x%llx not found" DS_EOL, 2996*7697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)hdl); 2997*7697SMichael.Christensen@Sun.COM 2998*7697SMichael.Christensen@Sun.COM return (NULL); 2999*7697SMichael.Christensen@Sun.COM } 3000*7697SMichael.Christensen@Sun.COM 3001*7697SMichael.Christensen@Sun.COM static ds_svc_t * 3002*7697SMichael.Christensen@Sun.COM ds_svc_clone(ds_svc_t *svc) 3003*7697SMichael.Christensen@Sun.COM { 3004*7697SMichael.Christensen@Sun.COM ds_svc_t *newsvc; 3005*7697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 3006*7697SMichael.Christensen@Sun.COM 3007*7697SMichael.Christensen@Sun.COM ASSERT(svc->flags & DSSF_ISCLIENT); 3008*7697SMichael.Christensen@Sun.COM 3009*7697SMichael.Christensen@Sun.COM newsvc = ds_alloc_svc(); 3010*7697SMichael.Christensen@Sun.COM 3011*7697SMichael.Christensen@Sun.COM /* Can only clone clients for now */ 3012*7697SMichael.Christensen@Sun.COM hdl = newsvc->hdl | DS_HDL_ISCLIENT_BIT; 3013*7697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: cloning client: old hdl: 0x%llx new hdl: " 3014*7697SMichael.Christensen@Sun.COM "0x%llx" DS_EOL, __func__, (u_longlong_t)svc->hdl, 3015*7697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 3016*7697SMichael.Christensen@Sun.COM (void) memcpy(newsvc, svc, sizeof (ds_svc_t)); 3017*7697SMichael.Christensen@Sun.COM newsvc->hdl = hdl; 3018*7697SMichael.Christensen@Sun.COM newsvc->flags &= ~DSSF_LOOPBACK; 3019*7697SMichael.Christensen@Sun.COM newsvc->port = NULL; 3020*7697SMichael.Christensen@Sun.COM newsvc->svc_hdl = DS_BADHDL2; 3021*7697SMichael.Christensen@Sun.COM newsvc->cap.svc_id = ds_strdup(svc->cap.svc_id); 3022*7697SMichael.Christensen@Sun.COM newsvc->cap.vers = DS_MALLOC(svc->cap.nvers * sizeof (ds_ver_t)); 3023*7697SMichael.Christensen@Sun.COM (void) memcpy(newsvc->cap.vers, svc->cap.vers, 3024*7697SMichael.Christensen@Sun.COM svc->cap.nvers * sizeof (ds_ver_t)); 3025*7697SMichael.Christensen@Sun.COM 3026*7697SMichael.Christensen@Sun.COM /* 3027*7697SMichael.Christensen@Sun.COM * Kludge to allow lds driver user callbacks to get access to current 3028*7697SMichael.Christensen@Sun.COM * svc structure. Arg could be index to svc table or some other piece 3029*7697SMichael.Christensen@Sun.COM * of info to get to the svc table entry. 3030*7697SMichael.Christensen@Sun.COM */ 3031*7697SMichael.Christensen@Sun.COM if (newsvc->flags & DSSF_ISUSER) { 3032*7697SMichael.Christensen@Sun.COM newsvc->ops.cb_arg = (ds_cb_arg_t)(newsvc); 3033*7697SMichael.Christensen@Sun.COM } 3034*7697SMichael.Christensen@Sun.COM return (newsvc); 3035*7697SMichael.Christensen@Sun.COM } 3036*7697SMichael.Christensen@Sun.COM 3037*7697SMichael.Christensen@Sun.COM /* 3038*7697SMichael.Christensen@Sun.COM * Internal handle lookup function. 3039*7697SMichael.Christensen@Sun.COM */ 3040*7697SMichael.Christensen@Sun.COM static int 3041*7697SMichael.Christensen@Sun.COM i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 3042*7697SMichael.Christensen@Sun.COM uint_t maxhdls) 3043*7697SMichael.Christensen@Sun.COM { 3044*7697SMichael.Christensen@Sun.COM int idx; 3045*7697SMichael.Christensen@Sun.COM int nhdls = 0; 3046*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 3047*7697SMichael.Christensen@Sun.COM uint32_t client_flag = is_client ? DSSF_ISCLIENT : 0; 3048*7697SMichael.Christensen@Sun.COM 3049*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 3050*7697SMichael.Christensen@Sun.COM 3051*7697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs && nhdls < maxhdls; idx++) { 3052*7697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 3053*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 3054*7697SMichael.Christensen@Sun.COM continue; 3055*7697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, service) == 0 && 3056*7697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) == client_flag) { 3057*7697SMichael.Christensen@Sun.COM if (hdlp != NULL && nhdls < maxhdls) { 3058*7697SMichael.Christensen@Sun.COM hdlp[nhdls] = svc->hdl; 3059*7697SMichael.Christensen@Sun.COM nhdls++; 3060*7697SMichael.Christensen@Sun.COM } else { 3061*7697SMichael.Christensen@Sun.COM nhdls++; 3062*7697SMichael.Christensen@Sun.COM } 3063*7697SMichael.Christensen@Sun.COM } 3064*7697SMichael.Christensen@Sun.COM } 3065*7697SMichael.Christensen@Sun.COM return (nhdls); 3066*7697SMichael.Christensen@Sun.COM } 3067*7697SMichael.Christensen@Sun.COM 3068*7697SMichael.Christensen@Sun.COM /* 3069*7697SMichael.Christensen@Sun.COM * Interface for ds_hdl_lookup in lds driver. 3070*7697SMichael.Christensen@Sun.COM */ 3071*7697SMichael.Christensen@Sun.COM int 3072*7697SMichael.Christensen@Sun.COM ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 3073*7697SMichael.Christensen@Sun.COM uint_t maxhdls, uint_t *nhdlsp) 3074*7697SMichael.Christensen@Sun.COM { 3075*7697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 3076*7697SMichael.Christensen@Sun.COM *nhdlsp = i_ds_hdl_lookup(service, is_client, hdlp, maxhdls); 3077*7697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 3078*7697SMichael.Christensen@Sun.COM return (0); 3079*7697SMichael.Christensen@Sun.COM } 3080*7697SMichael.Christensen@Sun.COM 3081*7697SMichael.Christensen@Sun.COM static void 3082*7697SMichael.Christensen@Sun.COM ds_portset_del_active_clients(char *service, ds_portset_t *portsp) 3083*7697SMichael.Christensen@Sun.COM { 3084*7697SMichael.Christensen@Sun.COM ds_portset_t ports = *portsp; 3085*7697SMichael.Christensen@Sun.COM int idx; 3086*7697SMichael.Christensen@Sun.COM ds_svc_t *svc; 3087*7697SMichael.Christensen@Sun.COM 3088*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 3089*7697SMichael.Christensen@Sun.COM 3090*7697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 3091*7697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 3092*7697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 3093*7697SMichael.Christensen@Sun.COM continue; 3094*7697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, service) == 0 && 3095*7697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) != 0 && 3096*7697SMichael.Christensen@Sun.COM svc->state != DS_SVC_INACTIVE && 3097*7697SMichael.Christensen@Sun.COM svc->port != NULL) { 3098*7697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(ports, PORTID(svc->port)); 3099*7697SMichael.Christensen@Sun.COM } 3100*7697SMichael.Christensen@Sun.COM } 3101*7697SMichael.Christensen@Sun.COM *portsp = ports; 3102*7697SMichael.Christensen@Sun.COM } 3103*7697SMichael.Christensen@Sun.COM 3104*7697SMichael.Christensen@Sun.COM /* 3105*7697SMichael.Christensen@Sun.COM * After an UNREG REQ, check if this is a client service with multiple 3106*7697SMichael.Christensen@Sun.COM * handles. If it is, then we can eliminate this entry. 3107*7697SMichael.Christensen@Sun.COM */ 3108*7697SMichael.Christensen@Sun.COM static void 3109*7697SMichael.Christensen@Sun.COM ds_check_for_dup_services(ds_svc_t *svc) 3110*7697SMichael.Christensen@Sun.COM { 3111*7697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != 0 && 3112*7697SMichael.Christensen@Sun.COM svc->state == DS_SVC_INACTIVE && 3113*7697SMichael.Christensen@Sun.COM i_ds_hdl_lookup(svc->cap.svc_id, 1, NULL, 2) == 2) { 3114*7697SMichael.Christensen@Sun.COM ds_delete_svc_entry(svc); 3115*7697SMichael.Christensen@Sun.COM } 3116*7697SMichael.Christensen@Sun.COM } 3117*7697SMichael.Christensen@Sun.COM 3118*7697SMichael.Christensen@Sun.COM static void 3119*7697SMichael.Christensen@Sun.COM ds_delete_svc_entry(ds_svc_t *svc) 3120*7697SMichael.Christensen@Sun.COM { 3121*7697SMichael.Christensen@Sun.COM ds_svc_hdl_t tmp_hdl; 3122*7697SMichael.Christensen@Sun.COM 3123*7697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 3124*7697SMichael.Christensen@Sun.COM 3125*7697SMichael.Christensen@Sun.COM /* 3126*7697SMichael.Christensen@Sun.COM * Clear out the structure, but do not deallocate the 3127*7697SMichael.Christensen@Sun.COM * memory. It can be reused for the next registration. 3128*7697SMichael.Christensen@Sun.COM */ 3129*7697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1); 3130*7697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t)); 3131*7697SMichael.Christensen@Sun.COM 3132*7697SMichael.Christensen@Sun.COM /* save the handle to prevent reuse */ 3133*7697SMichael.Christensen@Sun.COM tmp_hdl = svc->hdl; 3134*7697SMichael.Christensen@Sun.COM bzero((void *)svc, sizeof (ds_svc_t)); 3135*7697SMichael.Christensen@Sun.COM 3136*7697SMichael.Christensen@Sun.COM /* initialize for next use */ 3137*7697SMichael.Christensen@Sun.COM svc->hdl = tmp_hdl; 3138*7697SMichael.Christensen@Sun.COM svc->state = DS_SVC_FREE; 3139*7697SMichael.Christensen@Sun.COM 3140*7697SMichael.Christensen@Sun.COM ds_svcs.nsvcs--; 3141*7697SMichael.Christensen@Sun.COM } 3142