17697SMichael.Christensen@Sun.COM /* 27697SMichael.Christensen@Sun.COM * CDDL HEADER START 37697SMichael.Christensen@Sun.COM * 47697SMichael.Christensen@Sun.COM * The contents of this file are subject to the terms of the 57697SMichael.Christensen@Sun.COM * Common Development and Distribution License (the "License"). 67697SMichael.Christensen@Sun.COM * You may not use this file except in compliance with the License. 77697SMichael.Christensen@Sun.COM * 87697SMichael.Christensen@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97697SMichael.Christensen@Sun.COM * or http://www.opensolaris.org/os/licensing. 107697SMichael.Christensen@Sun.COM * See the License for the specific language governing permissions 117697SMichael.Christensen@Sun.COM * and limitations under the License. 127697SMichael.Christensen@Sun.COM * 137697SMichael.Christensen@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147697SMichael.Christensen@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157697SMichael.Christensen@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167697SMichael.Christensen@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177697SMichael.Christensen@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187697SMichael.Christensen@Sun.COM * 197697SMichael.Christensen@Sun.COM * CDDL HEADER END 207697SMichael.Christensen@Sun.COM */ 217697SMichael.Christensen@Sun.COM 227697SMichael.Christensen@Sun.COM /* 238894SMichael.Christensen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247697SMichael.Christensen@Sun.COM * Use is subject to license terms. 257697SMichael.Christensen@Sun.COM */ 267697SMichael.Christensen@Sun.COM 277697SMichael.Christensen@Sun.COM /* 287697SMichael.Christensen@Sun.COM * Domain Services Module Common Code. 297697SMichael.Christensen@Sun.COM * 307697SMichael.Christensen@Sun.COM * This module is intended to be used by both Solaris and the VBSC 317697SMichael.Christensen@Sun.COM * module. 327697SMichael.Christensen@Sun.COM */ 337697SMichael.Christensen@Sun.COM 347697SMichael.Christensen@Sun.COM #include <sys/modctl.h> 357697SMichael.Christensen@Sun.COM #include <sys/ksynch.h> 367697SMichael.Christensen@Sun.COM #include <sys/taskq.h> 377697SMichael.Christensen@Sun.COM #include <sys/disp.h> 387697SMichael.Christensen@Sun.COM #include <sys/cmn_err.h> 397697SMichael.Christensen@Sun.COM #include <sys/note.h> 407697SMichael.Christensen@Sun.COM #include <sys/mach_descrip.h> 417697SMichael.Christensen@Sun.COM #include <sys/mdesc.h> 427697SMichael.Christensen@Sun.COM #include <sys/ldc.h> 437697SMichael.Christensen@Sun.COM #include <sys/ds.h> 447697SMichael.Christensen@Sun.COM #include <sys/ds_impl.h> 457697SMichael.Christensen@Sun.COM 467697SMichael.Christensen@Sun.COM #ifndef MIN 477697SMichael.Christensen@Sun.COM #define MIN(a, b) ((a) < (b) ? (a) : (b)) 487697SMichael.Christensen@Sun.COM #endif 497697SMichael.Christensen@Sun.COM 507697SMichael.Christensen@Sun.COM #define DS_DECODE_BUF_LEN 30 517697SMichael.Christensen@Sun.COM 527697SMichael.Christensen@Sun.COM /* 537697SMichael.Christensen@Sun.COM * All DS ports in the system 547697SMichael.Christensen@Sun.COM * 557697SMichael.Christensen@Sun.COM * The list of DS ports is read in from the MD when the DS module is 567697SMichael.Christensen@Sun.COM * initialized and is never modified. This eliminates the need for 577697SMichael.Christensen@Sun.COM * locking to access the port array itself. Access to the individual 587697SMichael.Christensen@Sun.COM * ports are synchronized at the port level. 597697SMichael.Christensen@Sun.COM */ 607697SMichael.Christensen@Sun.COM ds_port_t ds_ports[DS_MAX_PORTS]; 617697SMichael.Christensen@Sun.COM ds_portset_t ds_allports; /* all DS ports in the system */ 629535SMichael.Christensen@Sun.COM ds_portset_t ds_nullport; /* allows test against null portset */ 637697SMichael.Christensen@Sun.COM 649603SMichael.Christensen@Sun.COM /* DS SP port id */ 659603SMichael.Christensen@Sun.COM uint64_t ds_sp_port_id = DS_PORTID_INVALID; 669603SMichael.Christensen@Sun.COM 677697SMichael.Christensen@Sun.COM /* 687697SMichael.Christensen@Sun.COM * Table of registered services 697697SMichael.Christensen@Sun.COM * 707697SMichael.Christensen@Sun.COM * Locking: Accesses to the table of services are synchronized using 717697SMichael.Christensen@Sun.COM * a mutex lock. The reader lock must be held when looking up service 727697SMichael.Christensen@Sun.COM * information in the table. The writer lock must be held when any 737697SMichael.Christensen@Sun.COM * service information is being modified. 747697SMichael.Christensen@Sun.COM */ 757697SMichael.Christensen@Sun.COM ds_svcs_t ds_svcs; 767697SMichael.Christensen@Sun.COM 777697SMichael.Christensen@Sun.COM /* 787697SMichael.Christensen@Sun.COM * Flag to prevent callbacks while in the middle of DS teardown. 797697SMichael.Christensen@Sun.COM */ 807697SMichael.Christensen@Sun.COM boolean_t ds_enabled = B_FALSE; /* enable/disable taskq processing */ 817697SMichael.Christensen@Sun.COM 827697SMichael.Christensen@Sun.COM /* 837697SMichael.Christensen@Sun.COM * Retry count and delay for LDC reads and writes 847697SMichael.Christensen@Sun.COM */ 857697SMichael.Christensen@Sun.COM #ifndef DS_DEFAULT_RETRIES 867697SMichael.Christensen@Sun.COM #define DS_DEFAULT_RETRIES 10000 /* number of times to retry */ 877697SMichael.Christensen@Sun.COM #endif 887697SMichael.Christensen@Sun.COM #ifndef DS_DEFAULT_DELAY 897697SMichael.Christensen@Sun.COM #define DS_DEFAULT_DELAY 1000 /* usecs to wait between retries */ 907697SMichael.Christensen@Sun.COM #endif 917697SMichael.Christensen@Sun.COM 927697SMichael.Christensen@Sun.COM static int ds_retries = DS_DEFAULT_RETRIES; 937697SMichael.Christensen@Sun.COM static clock_t ds_delay = DS_DEFAULT_DELAY; 947697SMichael.Christensen@Sun.COM 957697SMichael.Christensen@Sun.COM /* 967697SMichael.Christensen@Sun.COM * Supported versions of the DS message protocol 977697SMichael.Christensen@Sun.COM * 987697SMichael.Christensen@Sun.COM * The version array must be sorted in order from the highest 997697SMichael.Christensen@Sun.COM * supported version to the lowest. Support for a particular 1007697SMichael.Christensen@Sun.COM * <major>.<minor> version implies all lower minor versions of 1017697SMichael.Christensen@Sun.COM * that same major version are supported as well. 1027697SMichael.Christensen@Sun.COM */ 1037697SMichael.Christensen@Sun.COM static ds_ver_t ds_vers[] = { { 1, 0 } }; 1047697SMichael.Christensen@Sun.COM 1057697SMichael.Christensen@Sun.COM #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_vers[0])) 1067697SMichael.Christensen@Sun.COM 1077697SMichael.Christensen@Sun.COM 1087697SMichael.Christensen@Sun.COM /* incoming message handling functions */ 1097697SMichael.Christensen@Sun.COM typedef void (*ds_msg_handler_t)(ds_port_t *port, caddr_t buf, size_t len); 1107697SMichael.Christensen@Sun.COM static void ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len); 1117697SMichael.Christensen@Sun.COM static void ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len); 1127697SMichael.Christensen@Sun.COM static void ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len); 1137697SMichael.Christensen@Sun.COM static void ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len); 1147697SMichael.Christensen@Sun.COM static void ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len); 1157697SMichael.Christensen@Sun.COM static void ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len); 1167697SMichael.Christensen@Sun.COM static void ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len); 1177697SMichael.Christensen@Sun.COM static void ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len); 1187697SMichael.Christensen@Sun.COM static void ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len); 1197697SMichael.Christensen@Sun.COM static void ds_handle_data(ds_port_t *port, caddr_t buf, size_t len); 1207697SMichael.Christensen@Sun.COM static void ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len); 1217697SMichael.Christensen@Sun.COM 1227697SMichael.Christensen@Sun.COM /* 1237697SMichael.Christensen@Sun.COM * DS Message Handler Dispatch Table 1247697SMichael.Christensen@Sun.COM * 1257697SMichael.Christensen@Sun.COM * A table used to dispatch all incoming messages. This table 1267697SMichael.Christensen@Sun.COM * contains handlers for all the fixed message types, as well as 1277697SMichael.Christensen@Sun.COM * the the messages defined in the 1.0 version of the DS protocol. 1287697SMichael.Christensen@Sun.COM * The handlers are indexed based on the DS header msg_type values 1297697SMichael.Christensen@Sun.COM */ 1307697SMichael.Christensen@Sun.COM static const ds_msg_handler_t ds_msg_handlers[] = { 1317697SMichael.Christensen@Sun.COM ds_handle_init_req, /* DS_INIT_REQ */ 1327697SMichael.Christensen@Sun.COM ds_handle_init_ack, /* DS_INIT_ACK */ 1337697SMichael.Christensen@Sun.COM ds_handle_init_nack, /* DS_INIT_NACK */ 1347697SMichael.Christensen@Sun.COM ds_handle_reg_req, /* DS_REG_REQ */ 1357697SMichael.Christensen@Sun.COM ds_handle_reg_ack, /* DS_REG_ACK */ 1367697SMichael.Christensen@Sun.COM ds_handle_reg_nack, /* DS_REG_NACK */ 1377697SMichael.Christensen@Sun.COM ds_handle_unreg_req, /* DS_UNREG */ 1387697SMichael.Christensen@Sun.COM ds_handle_unreg_ack, /* DS_UNREG_ACK */ 1397697SMichael.Christensen@Sun.COM ds_handle_unreg_nack, /* DS_UNREG_NACK */ 1407697SMichael.Christensen@Sun.COM ds_handle_data, /* DS_DATA */ 1417697SMichael.Christensen@Sun.COM ds_handle_nack /* DS_NACK */ 1427697SMichael.Christensen@Sun.COM }; 1437697SMichael.Christensen@Sun.COM 1447697SMichael.Christensen@Sun.COM 1457697SMichael.Christensen@Sun.COM 1467697SMichael.Christensen@Sun.COM /* initialization functions */ 1477697SMichael.Christensen@Sun.COM static int ds_ldc_init(ds_port_t *port); 1487697SMichael.Christensen@Sun.COM 1497697SMichael.Christensen@Sun.COM /* event processing functions */ 1507697SMichael.Christensen@Sun.COM static uint_t ds_ldc_cb(uint64_t event, caddr_t arg); 1517697SMichael.Christensen@Sun.COM static int ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep); 1527697SMichael.Christensen@Sun.COM static void ds_handle_up_event(ds_port_t *port); 1537697SMichael.Christensen@Sun.COM static void ds_handle_down_reset_events(ds_port_t *port); 1547697SMichael.Christensen@Sun.COM static void ds_handle_recv(void *arg); 1557697SMichael.Christensen@Sun.COM static void ds_dispatch_event(void *arg); 1567697SMichael.Christensen@Sun.COM 1577697SMichael.Christensen@Sun.COM /* message sending functions */ 1587697SMichael.Christensen@Sun.COM static int ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen); 1597697SMichael.Christensen@Sun.COM static int ds_send_reg_req(ds_svc_t *svc, ds_port_t *port); 1607697SMichael.Christensen@Sun.COM static void ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl); 1617697SMichael.Christensen@Sun.COM static void ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl); 1627697SMichael.Christensen@Sun.COM 1637697SMichael.Christensen@Sun.COM /* walker functions */ 1647697SMichael.Christensen@Sun.COM static int ds_svc_isfree(ds_svc_t *svc, void *arg); 1657697SMichael.Christensen@Sun.COM static int ds_svc_unregister(ds_svc_t *svc, void *arg); 1667697SMichael.Christensen@Sun.COM static int ds_svc_port_up(ds_svc_t *svc, void *arg); 1677697SMichael.Christensen@Sun.COM 1687697SMichael.Christensen@Sun.COM /* service utilities */ 1697697SMichael.Christensen@Sun.COM static void ds_reset_svc(ds_svc_t *svc, ds_port_t *port); 1707697SMichael.Christensen@Sun.COM static int ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port); 17110042SMichael.Christensen@Sun.COM static int ds_svc_register_onport_walker(ds_svc_t *svc, void *arg); 17210042SMichael.Christensen@Sun.COM static void ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor); 1737697SMichael.Christensen@Sun.COM 1747697SMichael.Christensen@Sun.COM /* port utilities */ 1757697SMichael.Christensen@Sun.COM static void ds_port_reset(ds_port_t *port); 1767697SMichael.Christensen@Sun.COM static ldc_status_t ds_update_ldc_state(ds_port_t *port); 1777697SMichael.Christensen@Sun.COM 1787697SMichael.Christensen@Sun.COM /* misc utilities */ 1797697SMichael.Christensen@Sun.COM static void min_max_versions(int num_versions, ds_ver_t *sup_versionsp, 1807697SMichael.Christensen@Sun.COM uint16_t *min_major, uint16_t *max_major); 1817697SMichael.Christensen@Sun.COM 1827697SMichael.Christensen@Sun.COM /* debug */ 1837697SMichael.Christensen@Sun.COM static char *decode_ldc_events(uint64_t event, char *buf); 1847697SMichael.Christensen@Sun.COM 1857697SMichael.Christensen@Sun.COM /* loopback */ 1867697SMichael.Christensen@Sun.COM static void ds_loopback_register(ds_svc_hdl_t hdl); 1877697SMichael.Christensen@Sun.COM static void ds_loopback_unregister(ds_svc_hdl_t hdl); 1887697SMichael.Christensen@Sun.COM static void ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen); 1898172SMichael.Christensen@Sun.COM static int ds_loopback_set_svc(ds_svc_t *svc, ds_capability_t *cap, 1908172SMichael.Christensen@Sun.COM ds_svc_hdl_t *lb_hdlp); 1917697SMichael.Christensen@Sun.COM 1927697SMichael.Christensen@Sun.COM /* client handling */ 1937697SMichael.Christensen@Sun.COM static int i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 1947697SMichael.Christensen@Sun.COM uint_t maxhdls); 1957697SMichael.Christensen@Sun.COM static ds_svc_t *ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl, 1967697SMichael.Christensen@Sun.COM ds_port_t *port); 1977697SMichael.Christensen@Sun.COM static ds_svc_t *ds_find_svc_by_id_port(char *svc_id, int is_client, 1987697SMichael.Christensen@Sun.COM ds_port_t *port); 1997697SMichael.Christensen@Sun.COM static ds_svc_t *ds_svc_clone(ds_svc_t *svc); 2007697SMichael.Christensen@Sun.COM static void ds_check_for_dup_services(ds_svc_t *svc); 2017697SMichael.Christensen@Sun.COM static void ds_delete_svc_entry(ds_svc_t *svc); 2027697SMichael.Christensen@Sun.COM 2037697SMichael.Christensen@Sun.COM char * 2047697SMichael.Christensen@Sun.COM ds_strdup(char *str) 2057697SMichael.Christensen@Sun.COM { 2067697SMichael.Christensen@Sun.COM char *newstr; 2077697SMichael.Christensen@Sun.COM 2087697SMichael.Christensen@Sun.COM newstr = DS_MALLOC(strlen(str) + 1); 2097697SMichael.Christensen@Sun.COM (void) strcpy(newstr, str); 2107697SMichael.Christensen@Sun.COM return (newstr); 2117697SMichael.Christensen@Sun.COM } 2127697SMichael.Christensen@Sun.COM 2137697SMichael.Christensen@Sun.COM void 2147697SMichael.Christensen@Sun.COM ds_common_init(void) 2157697SMichael.Christensen@Sun.COM { 2167697SMichael.Christensen@Sun.COM /* Validate version table */ 2177697SMichael.Christensen@Sun.COM ASSERT(ds_vers_isvalid(ds_vers, DS_NUM_VER) == DS_VERS_OK); 2187697SMichael.Christensen@Sun.COM 2197697SMichael.Christensen@Sun.COM /* Initialize services table */ 2207697SMichael.Christensen@Sun.COM ds_init_svcs_tbl(DS_MAXSVCS_INIT); 2217697SMichael.Christensen@Sun.COM 2227697SMichael.Christensen@Sun.COM /* enable callback processing */ 2237697SMichael.Christensen@Sun.COM ds_enabled = B_TRUE; 2247697SMichael.Christensen@Sun.COM } 2257697SMichael.Christensen@Sun.COM 2267697SMichael.Christensen@Sun.COM /* BEGIN LDC SUPPORT FUNCTIONS */ 2277697SMichael.Christensen@Sun.COM 2287697SMichael.Christensen@Sun.COM static char * 2297697SMichael.Christensen@Sun.COM decode_ldc_events(uint64_t event, char *buf) 2307697SMichael.Christensen@Sun.COM { 2317697SMichael.Christensen@Sun.COM buf[0] = 0; 2327697SMichael.Christensen@Sun.COM if (event & LDC_EVT_DOWN) (void) strcat(buf, " DOWN"); 2337697SMichael.Christensen@Sun.COM if (event & LDC_EVT_RESET) (void) strcat(buf, " RESET"); 2347697SMichael.Christensen@Sun.COM if (event & LDC_EVT_UP) (void) strcat(buf, " UP"); 2357697SMichael.Christensen@Sun.COM if (event & LDC_EVT_READ) (void) strcat(buf, " READ"); 2367697SMichael.Christensen@Sun.COM if (event & LDC_EVT_WRITE) (void) strcat(buf, " WRITE"); 2377697SMichael.Christensen@Sun.COM return (buf); 2387697SMichael.Christensen@Sun.COM } 2397697SMichael.Christensen@Sun.COM 2407697SMichael.Christensen@Sun.COM static ldc_status_t 2417697SMichael.Christensen@Sun.COM ds_update_ldc_state(ds_port_t *port) 2427697SMichael.Christensen@Sun.COM { 2437697SMichael.Christensen@Sun.COM ldc_status_t ldc_state; 2447697SMichael.Christensen@Sun.COM int rv; 2457697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 2467697SMichael.Christensen@Sun.COM 2477697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 2487697SMichael.Christensen@Sun.COM 2497697SMichael.Christensen@Sun.COM /* 2507697SMichael.Christensen@Sun.COM * Read status and update ldc state info in port structure. 2517697SMichael.Christensen@Sun.COM */ 2527697SMichael.Christensen@Sun.COM if ((rv = ldc_status(port->ldc.hdl, &ldc_state)) != 0) { 2537697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_status error: %s" DS_EOL, 2547697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 2557697SMichael.Christensen@Sun.COM ldc_state = port->ldc.state; 2567697SMichael.Christensen@Sun.COM } else { 2577697SMichael.Christensen@Sun.COM port->ldc.state = ldc_state; 2587697SMichael.Christensen@Sun.COM } 2597697SMichael.Christensen@Sun.COM 2607697SMichael.Christensen@Sun.COM return (ldc_state); 2617697SMichael.Christensen@Sun.COM } 2627697SMichael.Christensen@Sun.COM 2637697SMichael.Christensen@Sun.COM static void 2647697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(ds_port_t *port) 2657697SMichael.Christensen@Sun.COM { 2667697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port), 2677697SMichael.Christensen@Sun.COM __func__); 2687697SMichael.Christensen@Sun.COM 2697697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 2707697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 2717697SMichael.Christensen@Sun.COM 2727697SMichael.Christensen@Sun.COM ds_sys_drain_events(port); 2737697SMichael.Christensen@Sun.COM 2747697SMichael.Christensen@Sun.COM (void) ds_update_ldc_state(port); 2757697SMichael.Christensen@Sun.COM 2767697SMichael.Christensen@Sun.COM /* reset the port state */ 2777697SMichael.Christensen@Sun.COM ds_port_reset(port); 2787697SMichael.Christensen@Sun.COM 2797697SMichael.Christensen@Sun.COM /* acknowledge the reset */ 2807697SMichael.Christensen@Sun.COM (void) ldc_up(port->ldc.hdl); 2817697SMichael.Christensen@Sun.COM 2827697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 2837697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2847697SMichael.Christensen@Sun.COM 2857697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 2867697SMichael.Christensen@Sun.COM 2877697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 2887697SMichael.Christensen@Sun.COM } 2897697SMichael.Christensen@Sun.COM 2907697SMichael.Christensen@Sun.COM static void 2917697SMichael.Christensen@Sun.COM ds_handle_up_event(ds_port_t *port) 2927697SMichael.Christensen@Sun.COM { 2937697SMichael.Christensen@Sun.COM ldc_status_t ldc_state; 2947697SMichael.Christensen@Sun.COM 2957697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port), 2967697SMichael.Christensen@Sun.COM __func__); 2977697SMichael.Christensen@Sun.COM 2987697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 2997697SMichael.Christensen@Sun.COM 3007697SMichael.Christensen@Sun.COM ldc_state = ds_update_ldc_state(port); 3017697SMichael.Christensen@Sun.COM 3027697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 3037697SMichael.Christensen@Sun.COM 3047697SMichael.Christensen@Sun.COM if ((ldc_state == LDC_UP) && IS_DS_PORT(port)) { 3057697SMichael.Christensen@Sun.COM /* 3067697SMichael.Christensen@Sun.COM * Initiate the handshake. 3077697SMichael.Christensen@Sun.COM */ 3087697SMichael.Christensen@Sun.COM ds_send_init_req(port); 3097697SMichael.Christensen@Sun.COM } 3107697SMichael.Christensen@Sun.COM 3117697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 3127697SMichael.Christensen@Sun.COM } 3137697SMichael.Christensen@Sun.COM 3147697SMichael.Christensen@Sun.COM static uint_t 3157697SMichael.Christensen@Sun.COM ds_ldc_cb(uint64_t event, caddr_t arg) 3167697SMichael.Christensen@Sun.COM { 3177697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 3187697SMichael.Christensen@Sun.COM char evstring[DS_DECODE_BUF_LEN]; 3197697SMichael.Christensen@Sun.COM 3207697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: %s event (%llx) received" DS_EOL, 3217697SMichael.Christensen@Sun.COM PORTID(port), __func__, decode_ldc_events(event, evstring), 3227697SMichael.Christensen@Sun.COM (u_longlong_t)event); 3237697SMichael.Christensen@Sun.COM 3247697SMichael.Christensen@Sun.COM if (!ds_enabled) { 3257697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: callback handling is disabled" 3267697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__); 3277697SMichael.Christensen@Sun.COM return (LDC_SUCCESS); 3287697SMichael.Christensen@Sun.COM } 3297697SMichael.Christensen@Sun.COM 3307697SMichael.Christensen@Sun.COM if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) { 3317697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 3327697SMichael.Christensen@Sun.COM goto done; 3337697SMichael.Christensen@Sun.COM } 3347697SMichael.Christensen@Sun.COM 3357697SMichael.Christensen@Sun.COM if (event & LDC_EVT_UP) { 3367697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 3377697SMichael.Christensen@Sun.COM } 3387697SMichael.Christensen@Sun.COM 3397697SMichael.Christensen@Sun.COM if (event & LDC_EVT_READ) { 3407697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 3417697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: LDC READ event while " 3427697SMichael.Christensen@Sun.COM "port not up" DS_EOL, PORTID(port), __func__); 3437697SMichael.Christensen@Sun.COM goto done; 3447697SMichael.Christensen@Sun.COM } 3457697SMichael.Christensen@Sun.COM 3467697SMichael.Christensen@Sun.COM if (ds_sys_dispatch_func(ds_handle_recv, port)) { 3477697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: error initiating LDC READ " 3487697SMichael.Christensen@Sun.COM " event", PORTID(port)); 3497697SMichael.Christensen@Sun.COM } 3507697SMichael.Christensen@Sun.COM } 3517697SMichael.Christensen@Sun.COM 3527697SMichael.Christensen@Sun.COM if (event & LDC_EVT_WRITE) { 3537697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: LDC WRITE event received, " 3547697SMichael.Christensen@Sun.COM "not supported" DS_EOL, PORTID(port), __func__); 3557697SMichael.Christensen@Sun.COM } 3567697SMichael.Christensen@Sun.COM 3577697SMichael.Christensen@Sun.COM if (event & ~(LDC_EVT_UP | LDC_EVT_READ)) { 3587697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: Unexpected LDC event received: " 3597697SMichael.Christensen@Sun.COM "0x%llx" DS_EOL, PORTID(port), __func__, 3607697SMichael.Christensen@Sun.COM (u_longlong_t)event); 3617697SMichael.Christensen@Sun.COM } 3627697SMichael.Christensen@Sun.COM done: 3637697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 3647697SMichael.Christensen@Sun.COM 3657697SMichael.Christensen@Sun.COM return (LDC_SUCCESS); 3667697SMichael.Christensen@Sun.COM } 3677697SMichael.Christensen@Sun.COM 3687697SMichael.Christensen@Sun.COM static int 3697697SMichael.Christensen@Sun.COM ds_ldc_init(ds_port_t *port) 3707697SMichael.Christensen@Sun.COM { 3717697SMichael.Christensen@Sun.COM int rv; 3727697SMichael.Christensen@Sun.COM ldc_attr_t ldc_attr; 3737697SMichael.Christensen@Sun.COM caddr_t ldc_cb_arg = (caddr_t)port; 3747697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 3757697SMichael.Christensen@Sun.COM 3767697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 3777697SMichael.Christensen@Sun.COM 3787697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%lld" DS_EOL, 3797697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)port->ldc.id); 3807697SMichael.Christensen@Sun.COM 3817697SMichael.Christensen@Sun.COM ldc_attr.devclass = LDC_DEV_GENERIC; 3827697SMichael.Christensen@Sun.COM ldc_attr.instance = 0; 3837697SMichael.Christensen@Sun.COM ldc_attr.mode = LDC_MODE_RELIABLE; 3847697SMichael.Christensen@Sun.COM ldc_attr.mtu = DS_STREAM_MTU; 3857697SMichael.Christensen@Sun.COM 3867697SMichael.Christensen@Sun.COM if ((rv = ldc_init(port->ldc.id, &ldc_attr, &port->ldc.hdl)) != 0) { 3877697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_id: %lx, ldc_init error: %s" 3887697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, port->ldc.id, 3897697SMichael.Christensen@Sun.COM ds_errno_to_str(rv, ebuf)); 3907697SMichael.Christensen@Sun.COM return (rv); 3917697SMichael.Christensen@Sun.COM } 3927697SMichael.Christensen@Sun.COM 3937697SMichael.Christensen@Sun.COM rv = ldc_reg_callback(port->ldc.hdl, ds_ldc_cb, ldc_cb_arg); 3947697SMichael.Christensen@Sun.COM if (rv != 0) { 3957697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_reg_callback error: %s" 3967697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 3977697SMichael.Christensen@Sun.COM return (rv); 3987697SMichael.Christensen@Sun.COM } 3997697SMichael.Christensen@Sun.COM 4007697SMichael.Christensen@Sun.COM ds_sys_ldc_init(port); 4017697SMichael.Christensen@Sun.COM return (0); 4027697SMichael.Christensen@Sun.COM } 4037697SMichael.Christensen@Sun.COM 4047697SMichael.Christensen@Sun.COM int 4057697SMichael.Christensen@Sun.COM ds_ldc_fini(ds_port_t *port) 4067697SMichael.Christensen@Sun.COM { 4077697SMichael.Christensen@Sun.COM int rv; 4087697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 4097697SMichael.Christensen@Sun.COM 4107697SMichael.Christensen@Sun.COM ASSERT(port->state >= DS_PORT_LDC_INIT); 4119916SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 4127697SMichael.Christensen@Sun.COM 4137697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%ld" DS_EOL, PORTID(port), 4147697SMichael.Christensen@Sun.COM __func__, port->ldc.id); 4157697SMichael.Christensen@Sun.COM 4167697SMichael.Christensen@Sun.COM if ((rv = ldc_close(port->ldc.hdl)) != 0) { 4177697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_close error: %s" DS_EOL, 4187697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 4197697SMichael.Christensen@Sun.COM return (rv); 4207697SMichael.Christensen@Sun.COM } 4217697SMichael.Christensen@Sun.COM 4227697SMichael.Christensen@Sun.COM if ((rv = ldc_unreg_callback(port->ldc.hdl)) != 0) { 4237697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_unreg_callback error: %s" 4247697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 4257697SMichael.Christensen@Sun.COM return (rv); 4267697SMichael.Christensen@Sun.COM } 4277697SMichael.Christensen@Sun.COM 4287697SMichael.Christensen@Sun.COM if ((rv = ldc_fini(port->ldc.hdl)) != 0) { 4297697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_fini error: %s" DS_EOL, 4307697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 4317697SMichael.Christensen@Sun.COM return (rv); 4327697SMichael.Christensen@Sun.COM } 4337697SMichael.Christensen@Sun.COM 4349916SMichael.Christensen@Sun.COM port->ldc.id = (uint64_t)-1; 4359916SMichael.Christensen@Sun.COM port->ldc.hdl = NULL; 4369916SMichael.Christensen@Sun.COM port->ldc.state = 0; 4379916SMichael.Christensen@Sun.COM 4387697SMichael.Christensen@Sun.COM return (rv); 4397697SMichael.Christensen@Sun.COM } 4407697SMichael.Christensen@Sun.COM 4417697SMichael.Christensen@Sun.COM /* 4427697SMichael.Christensen@Sun.COM * Attempt to read a specified number of bytes from a particular LDC. 4437697SMichael.Christensen@Sun.COM * Returns zero for success or the return code from the LDC read on 4447697SMichael.Christensen@Sun.COM * failure. The actual number of bytes read from the LDC is returned 4457697SMichael.Christensen@Sun.COM * in the size parameter. 4467697SMichael.Christensen@Sun.COM */ 4477697SMichael.Christensen@Sun.COM static int 4487697SMichael.Christensen@Sun.COM ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep) 4497697SMichael.Christensen@Sun.COM { 4507697SMichael.Christensen@Sun.COM int rv = 0; 4517697SMichael.Christensen@Sun.COM size_t bytes_req = *sizep; 4527697SMichael.Christensen@Sun.COM size_t bytes_left = bytes_req; 4537697SMichael.Christensen@Sun.COM size_t nbytes; 4547697SMichael.Christensen@Sun.COM int retry_count = 0; 4557697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 4567697SMichael.Christensen@Sun.COM 4577697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->rcv_lock)); 4587697SMichael.Christensen@Sun.COM 4597697SMichael.Christensen@Sun.COM *sizep = 0; 4607697SMichael.Christensen@Sun.COM 4617697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: attempting to read %ld bytes" DS_EOL, 4627697SMichael.Christensen@Sun.COM PORTID(port), bytes_req); 4637697SMichael.Christensen@Sun.COM 4647697SMichael.Christensen@Sun.COM while (bytes_left > 0) { 4657697SMichael.Christensen@Sun.COM 4667697SMichael.Christensen@Sun.COM nbytes = bytes_left; 4677697SMichael.Christensen@Sun.COM 4689916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 4699916SMichael.Christensen@Sun.COM if (port->ldc.state == LDC_UP) { 4709916SMichael.Christensen@Sun.COM rv = ldc_read(port->ldc.hdl, msgp, &nbytes); 4719916SMichael.Christensen@Sun.COM } else 4729916SMichael.Christensen@Sun.COM rv = ENXIO; 4739916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 4749916SMichael.Christensen@Sun.COM if (rv != 0) { 4757697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 4767697SMichael.Christensen@Sun.COM break; 4777697SMichael.Christensen@Sun.COM } else if (rv != EAGAIN) { 4787697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "ds@%lx: %s: %s" DS_EOL, 4797697SMichael.Christensen@Sun.COM PORTID(port), __func__, 4807697SMichael.Christensen@Sun.COM ds_errno_to_str(rv, ebuf)); 4817697SMichael.Christensen@Sun.COM break; 4827697SMichael.Christensen@Sun.COM } 4837697SMichael.Christensen@Sun.COM } else { 4847697SMichael.Christensen@Sun.COM if (nbytes != 0) { 4857697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: " 4867697SMichael.Christensen@Sun.COM "read %ld bytes, %d retries" DS_EOL, 4877697SMichael.Christensen@Sun.COM PORTID(port), nbytes, retry_count); 4887697SMichael.Christensen@Sun.COM 4897697SMichael.Christensen@Sun.COM *sizep += nbytes; 4907697SMichael.Christensen@Sun.COM msgp += nbytes; 4917697SMichael.Christensen@Sun.COM bytes_left -= nbytes; 4927697SMichael.Christensen@Sun.COM 4937697SMichael.Christensen@Sun.COM /* reset counter on a successful read */ 4947697SMichael.Christensen@Sun.COM retry_count = 0; 4957697SMichael.Christensen@Sun.COM continue; 4967697SMichael.Christensen@Sun.COM } 4977697SMichael.Christensen@Sun.COM 4987697SMichael.Christensen@Sun.COM /* 4997697SMichael.Christensen@Sun.COM * No data was read. Check if this is the 5007697SMichael.Christensen@Sun.COM * first attempt. If so, just return since 5017697SMichael.Christensen@Sun.COM * nothing has been read yet. 5027697SMichael.Christensen@Sun.COM */ 5037697SMichael.Christensen@Sun.COM if (bytes_left == bytes_req) { 5047697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: read zero bytes, " 5057697SMichael.Christensen@Sun.COM " no data available" DS_EOL, PORTID(port)); 5067697SMichael.Christensen@Sun.COM break; 5077697SMichael.Christensen@Sun.COM } 5087697SMichael.Christensen@Sun.COM } 5097697SMichael.Christensen@Sun.COM 5107697SMichael.Christensen@Sun.COM /* 5117697SMichael.Christensen@Sun.COM * A retry is necessary because the read returned 5127697SMichael.Christensen@Sun.COM * EAGAIN, or a zero length read occurred after 5137697SMichael.Christensen@Sun.COM * reading a partial message. 5147697SMichael.Christensen@Sun.COM */ 5157697SMichael.Christensen@Sun.COM if (retry_count++ >= ds_retries) { 5167697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: timed out waiting for " 5177697SMichael.Christensen@Sun.COM "message" DS_EOL, PORTID(port)); 5187697SMichael.Christensen@Sun.COM break; 5197697SMichael.Christensen@Sun.COM } 5207697SMichael.Christensen@Sun.COM 5217697SMichael.Christensen@Sun.COM drv_usecwait(ds_delay); 5227697SMichael.Christensen@Sun.COM } 5237697SMichael.Christensen@Sun.COM 5247697SMichael.Christensen@Sun.COM return (rv); 5257697SMichael.Christensen@Sun.COM } 5267697SMichael.Christensen@Sun.COM 5277697SMichael.Christensen@Sun.COM static void 5287697SMichael.Christensen@Sun.COM ds_handle_recv(void *arg) 5297697SMichael.Christensen@Sun.COM { 5307697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 5317697SMichael.Christensen@Sun.COM char *hbuf; 5327697SMichael.Christensen@Sun.COM size_t msglen; 5337697SMichael.Christensen@Sun.COM size_t read_size; 5347697SMichael.Christensen@Sun.COM boolean_t hasdata; 5357697SMichael.Christensen@Sun.COM ds_hdr_t hdr; 5367697SMichael.Christensen@Sun.COM uint8_t *msg; 5377697SMichael.Christensen@Sun.COM char *currp; 5387697SMichael.Christensen@Sun.COM int rv; 5397697SMichael.Christensen@Sun.COM ds_event_t *devent; 5407697SMichael.Christensen@Sun.COM 5417697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s..." DS_EOL, PORTID(port), __func__); 5427697SMichael.Christensen@Sun.COM 5437697SMichael.Christensen@Sun.COM /* 5447697SMichael.Christensen@Sun.COM * Read messages from the channel until there are none 5457697SMichael.Christensen@Sun.COM * pending. Valid messages are dispatched to be handled 5467697SMichael.Christensen@Sun.COM * by a separate thread while any malformed messages are 5477697SMichael.Christensen@Sun.COM * dropped. 5487697SMichael.Christensen@Sun.COM */ 5497697SMichael.Christensen@Sun.COM 5507697SMichael.Christensen@Sun.COM mutex_enter(&port->rcv_lock); 5517697SMichael.Christensen@Sun.COM 5529916SMichael.Christensen@Sun.COM for (;;) { 5539916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 5549916SMichael.Christensen@Sun.COM if (port->ldc.state == LDC_UP) { 5559916SMichael.Christensen@Sun.COM rv = ldc_chkq(port->ldc.hdl, &hasdata); 5569916SMichael.Christensen@Sun.COM } else 5579916SMichael.Christensen@Sun.COM rv = ENXIO; 5589916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 5599916SMichael.Christensen@Sun.COM if (rv != 0 || !hasdata) 5609916SMichael.Christensen@Sun.COM break; 5617697SMichael.Christensen@Sun.COM 5627697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: %s: reading next message" DS_EOL, 5637697SMichael.Christensen@Sun.COM PORTID(port), __func__); 5647697SMichael.Christensen@Sun.COM 5657697SMichael.Christensen@Sun.COM /* 5667697SMichael.Christensen@Sun.COM * Read in the next message. 5677697SMichael.Christensen@Sun.COM */ 5687697SMichael.Christensen@Sun.COM hbuf = (char *)&hdr; 5697697SMichael.Christensen@Sun.COM bzero(hbuf, DS_HDR_SZ); 5707697SMichael.Christensen@Sun.COM read_size = DS_HDR_SZ; 5717697SMichael.Christensen@Sun.COM currp = hbuf; 5727697SMichael.Christensen@Sun.COM 5737697SMichael.Christensen@Sun.COM /* read in the message header */ 5747697SMichael.Christensen@Sun.COM if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) { 5757697SMichael.Christensen@Sun.COM break; 5767697SMichael.Christensen@Sun.COM } 5777697SMichael.Christensen@Sun.COM 5787697SMichael.Christensen@Sun.COM if (read_size < DS_HDR_SZ) { 5797697SMichael.Christensen@Sun.COM /* 5807697SMichael.Christensen@Sun.COM * A zero length read is a valid signal that 5817697SMichael.Christensen@Sun.COM * there is no data left on the channel. 5827697SMichael.Christensen@Sun.COM */ 5837697SMichael.Christensen@Sun.COM if (read_size != 0) { 5847697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: invalid message " 5857697SMichael.Christensen@Sun.COM "length, received %ld bytes, expected %ld" 5867697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), read_size, DS_HDR_SZ); 5877697SMichael.Christensen@Sun.COM } 5887697SMichael.Christensen@Sun.COM continue; 5897697SMichael.Christensen@Sun.COM } 5907697SMichael.Christensen@Sun.COM 5917697SMichael.Christensen@Sun.COM /* get payload size and allocate a buffer */ 5927697SMichael.Christensen@Sun.COM read_size = ((ds_hdr_t *)hbuf)->payload_len; 5937697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + read_size; 5947697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 5957697SMichael.Christensen@Sun.COM if (!msg) { 5967697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "Memory allocation failed attempting " 5977697SMichael.Christensen@Sun.COM " to allocate %d bytes." DS_EOL, (int)msglen); 5987697SMichael.Christensen@Sun.COM continue; 5997697SMichael.Christensen@Sun.COM } 6007697SMichael.Christensen@Sun.COM 6017697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: %s: message payload len %d" DS_EOL, 6027697SMichael.Christensen@Sun.COM PORTID(port), __func__, (int)read_size); 6037697SMichael.Christensen@Sun.COM 6047697SMichael.Christensen@Sun.COM /* move message header into buffer */ 6057697SMichael.Christensen@Sun.COM (void) memcpy(msg, hbuf, DS_HDR_SZ); 6067697SMichael.Christensen@Sun.COM currp = (char *)(msg) + DS_HDR_SZ; 6077697SMichael.Christensen@Sun.COM 6087697SMichael.Christensen@Sun.COM /* read in the message body */ 6097697SMichael.Christensen@Sun.COM if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) { 6107697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 6117697SMichael.Christensen@Sun.COM break; 6127697SMichael.Christensen@Sun.COM } 6137697SMichael.Christensen@Sun.COM 6147697SMichael.Christensen@Sun.COM /* validate the size of the message */ 6157697SMichael.Christensen@Sun.COM if ((DS_HDR_SZ + read_size) != msglen) { 6167697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: invalid message length, " 6177697SMichael.Christensen@Sun.COM "received %ld bytes, expected %ld" DS_EOL, 6187697SMichael.Christensen@Sun.COM PORTID(port), __func__, (DS_HDR_SZ + read_size), 6197697SMichael.Christensen@Sun.COM msglen); 6207697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 6217697SMichael.Christensen@Sun.COM continue; 6227697SMichael.Christensen@Sun.COM } 6237697SMichael.Christensen@Sun.COM 6247697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen); 6257697SMichael.Christensen@Sun.COM 6267697SMichael.Christensen@Sun.COM /* 6277697SMichael.Christensen@Sun.COM * Send the message for processing, and store it 6287697SMichael.Christensen@Sun.COM * in the log. The memory is deallocated only when 6297697SMichael.Christensen@Sun.COM * the message is removed from the log. 6307697SMichael.Christensen@Sun.COM */ 6317697SMichael.Christensen@Sun.COM 6327697SMichael.Christensen@Sun.COM devent = DS_MALLOC(sizeof (ds_event_t)); 6337697SMichael.Christensen@Sun.COM devent->port = port; 6347697SMichael.Christensen@Sun.COM devent->buf = (char *)msg; 6357697SMichael.Christensen@Sun.COM devent->buflen = msglen; 6367697SMichael.Christensen@Sun.COM 6377697SMichael.Christensen@Sun.COM /* log the message */ 6387697SMichael.Christensen@Sun.COM (void) ds_log_add_msg(DS_LOG_IN(port->id), msg, msglen); 6397697SMichael.Christensen@Sun.COM 6407697SMichael.Christensen@Sun.COM if (ds_sys_dispatch_func(ds_dispatch_event, devent)) { 6417697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: error initiating " 6427697SMichael.Christensen@Sun.COM "event handler", PORTID(port)); 6437697SMichael.Christensen@Sun.COM DS_FREE(devent, sizeof (ds_event_t)); 6447697SMichael.Christensen@Sun.COM } 6457697SMichael.Christensen@Sun.COM } 6467697SMichael.Christensen@Sun.COM 6477697SMichael.Christensen@Sun.COM mutex_exit(&port->rcv_lock); 6487697SMichael.Christensen@Sun.COM 6497697SMichael.Christensen@Sun.COM /* handle connection reset errors returned from ds_recv_msg */ 6507697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 6517697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 6527697SMichael.Christensen@Sun.COM } 6537697SMichael.Christensen@Sun.COM 6547697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s done" DS_EOL, PORTID(port), __func__); 6557697SMichael.Christensen@Sun.COM } 6567697SMichael.Christensen@Sun.COM 6577697SMichael.Christensen@Sun.COM static void 6587697SMichael.Christensen@Sun.COM ds_dispatch_event(void *arg) 6597697SMichael.Christensen@Sun.COM { 6607697SMichael.Christensen@Sun.COM ds_event_t *event = (ds_event_t *)arg; 6617697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 6627697SMichael.Christensen@Sun.COM ds_port_t *port; 6637697SMichael.Christensen@Sun.COM 6647697SMichael.Christensen@Sun.COM port = event->port; 6657697SMichael.Christensen@Sun.COM 6667697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)event->buf; 6677697SMichael.Christensen@Sun.COM 6687697SMichael.Christensen@Sun.COM if (DS_MSG_TYPE_VALID(hdr->msg_type)) { 6697697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: dispatch_event: msg_type=%d" DS_EOL, 6707697SMichael.Christensen@Sun.COM PORTID(port), hdr->msg_type); 6717697SMichael.Christensen@Sun.COM 6727697SMichael.Christensen@Sun.COM (*ds_msg_handlers[hdr->msg_type])(port, event->buf, 6737697SMichael.Christensen@Sun.COM event->buflen); 6747697SMichael.Christensen@Sun.COM } else { 6757697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: dispatch_event: invalid msg " 6767697SMichael.Christensen@Sun.COM "type (%d)" DS_EOL, PORTID(port), hdr->msg_type); 6777697SMichael.Christensen@Sun.COM } 6787697SMichael.Christensen@Sun.COM 6797697SMichael.Christensen@Sun.COM DS_FREE(event->buf, event->buflen); 6807697SMichael.Christensen@Sun.COM DS_FREE(event, sizeof (ds_event_t)); 6817697SMichael.Christensen@Sun.COM } 6827697SMichael.Christensen@Sun.COM 6837697SMichael.Christensen@Sun.COM int 6847697SMichael.Christensen@Sun.COM ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen) 6857697SMichael.Christensen@Sun.COM { 6867697SMichael.Christensen@Sun.COM int rv; 6877697SMichael.Christensen@Sun.COM caddr_t currp = msg; 6887697SMichael.Christensen@Sun.COM size_t amt_left = msglen; 6897697SMichael.Christensen@Sun.COM int loopcnt = 0; 6907697SMichael.Christensen@Sun.COM 6917697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s msglen: %ld" DS_EOL, PORTID(port), 6927697SMichael.Christensen@Sun.COM __func__, msglen); 6937697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen); 6947697SMichael.Christensen@Sun.COM 69510042SMichael.Christensen@Sun.COM (void) ds_log_add_msg(DS_LOG_OUT(port->id), (uint8_t *)msg, msglen); 69610042SMichael.Christensen@Sun.COM 6977697SMichael.Christensen@Sun.COM /* 6987697SMichael.Christensen@Sun.COM * Ensure that no other messages can be sent on this port by holding 6997697SMichael.Christensen@Sun.COM * the tx_lock mutex in case the write doesn't get sent with one write. 7007697SMichael.Christensen@Sun.COM * This guarantees that the message doesn't become fragmented. 7017697SMichael.Christensen@Sun.COM */ 7027697SMichael.Christensen@Sun.COM mutex_enter(&port->tx_lock); 7037697SMichael.Christensen@Sun.COM 7047697SMichael.Christensen@Sun.COM do { 7059916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 7069916SMichael.Christensen@Sun.COM if (port->ldc.state == LDC_UP) { 7079916SMichael.Christensen@Sun.COM rv = ldc_write(port->ldc.hdl, currp, &msglen); 7089916SMichael.Christensen@Sun.COM } else 7099916SMichael.Christensen@Sun.COM rv = ENXIO; 7109916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 7119916SMichael.Christensen@Sun.COM if (rv != 0) { 7127697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 7137697SMichael.Christensen@Sun.COM mutex_exit(&port->tx_lock); 714*10350SMichael.Christensen@Sun.COM (void) ds_sys_dispatch_func((void (*)(void *)) 715*10350SMichael.Christensen@Sun.COM ds_handle_down_reset_events, port); 7167697SMichael.Christensen@Sun.COM return (rv); 7177697SMichael.Christensen@Sun.COM } else if ((rv == EWOULDBLOCK) && 7187697SMichael.Christensen@Sun.COM (loopcnt++ < ds_retries)) { 7197697SMichael.Christensen@Sun.COM drv_usecwait(ds_delay); 7207697SMichael.Christensen@Sun.COM } else { 72110042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: send_msg: " 72210042SMichael.Christensen@Sun.COM "ldc_write failed (%d), %d bytes " 72310042SMichael.Christensen@Sun.COM "remaining" DS_EOL, PORTID(port), rv, 72410042SMichael.Christensen@Sun.COM (int)amt_left); 7257697SMichael.Christensen@Sun.COM goto error; 7267697SMichael.Christensen@Sun.COM } 7277697SMichael.Christensen@Sun.COM } else { 7287697SMichael.Christensen@Sun.COM amt_left -= msglen; 7297697SMichael.Christensen@Sun.COM currp += msglen; 7307697SMichael.Christensen@Sun.COM msglen = amt_left; 7317697SMichael.Christensen@Sun.COM loopcnt = 0; 7327697SMichael.Christensen@Sun.COM } 7337697SMichael.Christensen@Sun.COM } while (amt_left > 0); 7347697SMichael.Christensen@Sun.COM error: 7357697SMichael.Christensen@Sun.COM mutex_exit(&port->tx_lock); 7367697SMichael.Christensen@Sun.COM 7377697SMichael.Christensen@Sun.COM return (rv); 7387697SMichael.Christensen@Sun.COM } 7397697SMichael.Christensen@Sun.COM 7407697SMichael.Christensen@Sun.COM /* END LDC SUPPORT FUNCTIONS */ 7417697SMichael.Christensen@Sun.COM 7427697SMichael.Christensen@Sun.COM 7437697SMichael.Christensen@Sun.COM /* BEGIN DS PROTOCOL SUPPORT FUNCTIONS */ 7447697SMichael.Christensen@Sun.COM 7457697SMichael.Christensen@Sun.COM static void 7467697SMichael.Christensen@Sun.COM ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len) 7477697SMichael.Christensen@Sun.COM { 7487697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 7497697SMichael.Christensen@Sun.COM ds_init_ack_t *ack; 7507697SMichael.Christensen@Sun.COM ds_init_nack_t *nack; 7517697SMichael.Christensen@Sun.COM char *msg; 7527697SMichael.Christensen@Sun.COM size_t msglen; 7537697SMichael.Christensen@Sun.COM ds_init_req_t *req; 7547697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_req_t); 7557697SMichael.Christensen@Sun.COM uint16_t new_major; 7567697SMichael.Christensen@Sun.COM uint16_t new_minor; 7577697SMichael.Christensen@Sun.COM boolean_t match; 7587697SMichael.Christensen@Sun.COM 7597697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 7607697SMichael.Christensen@Sun.COM if (len != explen) { 7617697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <init_req: invalid message " 7627697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 7637697SMichael.Christensen@Sun.COM explen); 7647697SMichael.Christensen@Sun.COM return; 7657697SMichael.Christensen@Sun.COM } 7667697SMichael.Christensen@Sun.COM 7677697SMichael.Christensen@Sun.COM req = (ds_init_req_t *)(buf + DS_HDR_SZ); 7687697SMichael.Christensen@Sun.COM 7697697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_req: ver=%d.%d" DS_EOL, 7707697SMichael.Christensen@Sun.COM PORTID(port), req->major_vers, req->minor_vers); 7717697SMichael.Christensen@Sun.COM 7727697SMichael.Christensen@Sun.COM match = negotiate_version(DS_NUM_VER, &ds_vers[0], 7737697SMichael.Christensen@Sun.COM req->major_vers, &new_major, &new_minor); 7747697SMichael.Christensen@Sun.COM 7757697SMichael.Christensen@Sun.COM /* 7767697SMichael.Christensen@Sun.COM * Check version info. ACK only if the major numbers exactly 7777697SMichael.Christensen@Sun.COM * match. The service entity can retry with a new minor 7787697SMichael.Christensen@Sun.COM * based on the response sent as part of the NACK. 7797697SMichael.Christensen@Sun.COM */ 7807697SMichael.Christensen@Sun.COM if (match) { 7817697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_init_ack_t); 7827697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 7837697SMichael.Christensen@Sun.COM 7847697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 7857697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_ACK; 7867697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_ack_t); 7877697SMichael.Christensen@Sun.COM 7887697SMichael.Christensen@Sun.COM ack = (ds_init_ack_t *)(msg + DS_HDR_SZ); 7897697SMichael.Christensen@Sun.COM ack->minor_vers = MIN(new_minor, req->minor_vers); 7907697SMichael.Christensen@Sun.COM 7917697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_ack>: minor=0x%04X" DS_EOL, 7927697SMichael.Christensen@Sun.COM PORTID(port), MIN(new_minor, req->minor_vers)); 7937697SMichael.Christensen@Sun.COM } else { 7947697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_init_nack_t); 7957697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 7967697SMichael.Christensen@Sun.COM 7977697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 7987697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_NACK; 7997697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_nack_t); 8007697SMichael.Christensen@Sun.COM 8017697SMichael.Christensen@Sun.COM nack = (ds_init_nack_t *)(msg + DS_HDR_SZ); 8027697SMichael.Christensen@Sun.COM nack->major_vers = new_major; 8037697SMichael.Christensen@Sun.COM 8047697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_nack>: major=0x%04X" DS_EOL, 8057697SMichael.Christensen@Sun.COM PORTID(port), new_major); 8067697SMichael.Christensen@Sun.COM } 8077697SMichael.Christensen@Sun.COM 8087697SMichael.Christensen@Sun.COM /* 8097697SMichael.Christensen@Sun.COM * Send the response 8107697SMichael.Christensen@Sun.COM */ 8117697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 8127697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 81310042SMichael.Christensen@Sun.COM 81410042SMichael.Christensen@Sun.COM if (match) { 81510042SMichael.Christensen@Sun.COM ds_set_port_ready(port, req->major_vers, ack->minor_vers); 81610042SMichael.Christensen@Sun.COM } 8177697SMichael.Christensen@Sun.COM } 8187697SMichael.Christensen@Sun.COM 8197697SMichael.Christensen@Sun.COM static void 8207697SMichael.Christensen@Sun.COM ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len) 8217697SMichael.Christensen@Sun.COM { 8227697SMichael.Christensen@Sun.COM ds_init_ack_t *ack; 8237697SMichael.Christensen@Sun.COM ds_ver_t *ver; 82410042SMichael.Christensen@Sun.COM uint16_t major; 82510042SMichael.Christensen@Sun.COM uint16_t minor; 8267697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_ack_t); 8277697SMichael.Christensen@Sun.COM 8287697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 8297697SMichael.Christensen@Sun.COM if (len != explen) { 8307697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <init_ack: invalid message " 8317697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 8327697SMichael.Christensen@Sun.COM explen); 8337697SMichael.Christensen@Sun.COM return; 8347697SMichael.Christensen@Sun.COM } 8357697SMichael.Christensen@Sun.COM 8367697SMichael.Christensen@Sun.COM ack = (ds_init_ack_t *)(buf + DS_HDR_SZ); 8377697SMichael.Christensen@Sun.COM 8387697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 8397697SMichael.Christensen@Sun.COM 84010042SMichael.Christensen@Sun.COM if (port->state == DS_PORT_READY) { 84110042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready" DS_EOL, 84210042SMichael.Christensen@Sun.COM PORTID(port)); 84310042SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 84410042SMichael.Christensen@Sun.COM return; 84510042SMichael.Christensen@Sun.COM } 84610042SMichael.Christensen@Sun.COM 8477697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_INIT_REQ) { 8487697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: invalid state: %d" 8497697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 8507697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 8517697SMichael.Christensen@Sun.COM return; 8527697SMichael.Christensen@Sun.COM } 8537697SMichael.Christensen@Sun.COM 8547697SMichael.Christensen@Sun.COM ver = &(ds_vers[port->ver_idx]); 85510042SMichael.Christensen@Sun.COM major = ver->major; 85610042SMichael.Christensen@Sun.COM minor = MIN(ver->minor, ack->minor_vers); 85710042SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 8587697SMichael.Christensen@Sun.COM 8597697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready v%d.%d" DS_EOL, 86010042SMichael.Christensen@Sun.COM PORTID(port), major, minor); 86110042SMichael.Christensen@Sun.COM 86210042SMichael.Christensen@Sun.COM ds_set_port_ready(port, major, minor); 8637697SMichael.Christensen@Sun.COM } 8647697SMichael.Christensen@Sun.COM 8657697SMichael.Christensen@Sun.COM static void 8667697SMichael.Christensen@Sun.COM ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len) 8677697SMichael.Christensen@Sun.COM { 8687697SMichael.Christensen@Sun.COM int idx; 8697697SMichael.Christensen@Sun.COM ds_init_nack_t *nack; 8707697SMichael.Christensen@Sun.COM ds_ver_t *ver; 8717697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_nack_t); 8727697SMichael.Christensen@Sun.COM 8737697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 8747697SMichael.Christensen@Sun.COM if (len != explen) { 8757697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: invalid message " 8767697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 8777697SMichael.Christensen@Sun.COM explen); 8787697SMichael.Christensen@Sun.COM return; 8797697SMichael.Christensen@Sun.COM } 8807697SMichael.Christensen@Sun.COM 8817697SMichael.Christensen@Sun.COM nack = (ds_init_nack_t *)(buf + DS_HDR_SZ); 8827697SMichael.Christensen@Sun.COM 8837697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 8847697SMichael.Christensen@Sun.COM 8857697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_INIT_REQ) { 8867697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: invalid state: %d" 8877697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 8887697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 8897697SMichael.Christensen@Sun.COM return; 8907697SMichael.Christensen@Sun.COM } 8917697SMichael.Christensen@Sun.COM 8927697SMichael.Christensen@Sun.COM ver = &(ds_vers[port->ver_idx]); 8937697SMichael.Christensen@Sun.COM 8947697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: req=v%d.%d, nack=v%d.x" 8957697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), ver->major, ver->minor, nack->major_vers); 8967697SMichael.Christensen@Sun.COM 8977697SMichael.Christensen@Sun.COM if (nack->major_vers == 0) { 8987697SMichael.Christensen@Sun.COM /* no supported protocol version */ 8997697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS not supported" 9007697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 9017697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 9027697SMichael.Christensen@Sun.COM return; 9037697SMichael.Christensen@Sun.COM } 9047697SMichael.Christensen@Sun.COM 9057697SMichael.Christensen@Sun.COM /* 9067697SMichael.Christensen@Sun.COM * Walk the version list, looking for a major version 9077697SMichael.Christensen@Sun.COM * that is as close to the requested major version as 9087697SMichael.Christensen@Sun.COM * possible. 9097697SMichael.Christensen@Sun.COM */ 9107697SMichael.Christensen@Sun.COM for (idx = port->ver_idx; idx < DS_NUM_VER; idx++) { 9117697SMichael.Christensen@Sun.COM if (ds_vers[idx].major <= nack->major_vers) { 9127697SMichael.Christensen@Sun.COM /* found a version to try */ 9137697SMichael.Christensen@Sun.COM goto done; 9147697SMichael.Christensen@Sun.COM } 9157697SMichael.Christensen@Sun.COM } 9167697SMichael.Christensen@Sun.COM 9177697SMichael.Christensen@Sun.COM if (idx == DS_NUM_VER) { 9187697SMichael.Christensen@Sun.COM /* no supported version */ 9197697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS v%d.x not " 9207697SMichael.Christensen@Sun.COM "supported" DS_EOL, PORTID(port), nack->major_vers); 9217697SMichael.Christensen@Sun.COM 9227697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 9237697SMichael.Christensen@Sun.COM return; 9247697SMichael.Christensen@Sun.COM } 9257697SMichael.Christensen@Sun.COM 9267697SMichael.Christensen@Sun.COM done: 9277697SMichael.Christensen@Sun.COM /* start the handshake again */ 9287697SMichael.Christensen@Sun.COM port->ver_idx = idx; 9297697SMichael.Christensen@Sun.COM port->state = DS_PORT_LDC_INIT; 9307697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 9317697SMichael.Christensen@Sun.COM 9327697SMichael.Christensen@Sun.COM ds_send_init_req(port); 9337697SMichael.Christensen@Sun.COM 9347697SMichael.Christensen@Sun.COM } 9357697SMichael.Christensen@Sun.COM 9367697SMichael.Christensen@Sun.COM static ds_svc_t * 9377697SMichael.Christensen@Sun.COM ds_find_svc_by_id_port(char *svc_id, int is_client, ds_port_t *port) 9387697SMichael.Christensen@Sun.COM { 9397697SMichael.Christensen@Sun.COM int idx; 9407697SMichael.Christensen@Sun.COM ds_svc_t *svc, *found_svc = 0; 9417697SMichael.Christensen@Sun.COM uint32_t flag_match = is_client ? DSSF_ISCLIENT : 0; 9427697SMichael.Christensen@Sun.COM 9437697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 9447697SMichael.Christensen@Sun.COM 9457697SMichael.Christensen@Sun.COM /* walk every table entry */ 9467697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 9477697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 9487697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 9497697SMichael.Christensen@Sun.COM continue; 9507697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, svc_id) != 0) 9517697SMichael.Christensen@Sun.COM continue; 9527697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != flag_match) 9537697SMichael.Christensen@Sun.COM continue; 9547697SMichael.Christensen@Sun.COM if (port != NULL && svc->port == port) { 9557697SMichael.Christensen@Sun.COM return (svc); 9567697SMichael.Christensen@Sun.COM } else if (svc->state == DS_SVC_INACTIVE) { 9577697SMichael.Christensen@Sun.COM found_svc = svc; 9587697SMichael.Christensen@Sun.COM } else if (!found_svc) { 9597697SMichael.Christensen@Sun.COM found_svc = svc; 9607697SMichael.Christensen@Sun.COM } 9617697SMichael.Christensen@Sun.COM } 9627697SMichael.Christensen@Sun.COM 9637697SMichael.Christensen@Sun.COM return (found_svc); 9647697SMichael.Christensen@Sun.COM } 9657697SMichael.Christensen@Sun.COM 9667697SMichael.Christensen@Sun.COM static void 9677697SMichael.Christensen@Sun.COM ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len) 9687697SMichael.Christensen@Sun.COM { 9697697SMichael.Christensen@Sun.COM ds_reg_req_t *req; 9707697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 9717697SMichael.Christensen@Sun.COM ds_reg_ack_t *ack; 9727697SMichael.Christensen@Sun.COM ds_reg_nack_t *nack; 9737697SMichael.Christensen@Sun.COM char *msg; 9747697SMichael.Christensen@Sun.COM size_t msglen; 9757697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_req_t); 9767697SMichael.Christensen@Sun.COM ds_svc_t *svc = NULL; 9777697SMichael.Christensen@Sun.COM ds_ver_t version; 9787697SMichael.Christensen@Sun.COM uint16_t new_major; 9797697SMichael.Christensen@Sun.COM uint16_t new_minor; 9807697SMichael.Christensen@Sun.COM boolean_t match; 9817697SMichael.Christensen@Sun.COM 9827697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 9837697SMichael.Christensen@Sun.COM if (len < explen) { 9847697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_req: invalid message " 9857697SMichael.Christensen@Sun.COM "length (%ld), expected at least %ld" DS_EOL, 9867697SMichael.Christensen@Sun.COM PORTID(port), len, explen); 9877697SMichael.Christensen@Sun.COM return; 9887697SMichael.Christensen@Sun.COM } 9897697SMichael.Christensen@Sun.COM 9907697SMichael.Christensen@Sun.COM req = (ds_reg_req_t *)(buf + DS_HDR_SZ); 9917697SMichael.Christensen@Sun.COM 9927697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' ver=%d.%d, hdl=0x%llx" 9937697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), req->svc_id, req->major_vers, req->minor_vers, 9947697SMichael.Christensen@Sun.COM (u_longlong_t)req->svc_handle); 9957697SMichael.Christensen@Sun.COM 9967697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 9977697SMichael.Christensen@Sun.COM svc = ds_find_svc_by_id_port(req->svc_id, 9987697SMichael.Christensen@Sun.COM DS_HDL_ISCLIENT(req->svc_handle) == 0, port); 9997697SMichael.Christensen@Sun.COM if (svc == NULL) { 10007697SMichael.Christensen@Sun.COM 10017697SMichael.Christensen@Sun.COM do_reg_nack: 10027697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 10037697SMichael.Christensen@Sun.COM 10047697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_nack_t); 10057697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 10067697SMichael.Christensen@Sun.COM 10077697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 10087697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_NACK; 10097697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_nack_t); 10107697SMichael.Christensen@Sun.COM 10117697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ); 10127697SMichael.Christensen@Sun.COM nack->svc_handle = req->svc_handle; 10137697SMichael.Christensen@Sun.COM nack->result = DS_REG_VER_NACK; 10147697SMichael.Christensen@Sun.COM nack->major_vers = 0; 10157697SMichael.Christensen@Sun.COM 10167697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s'" DS_EOL, 10177697SMichael.Christensen@Sun.COM PORTID(port), req->svc_id); 10187697SMichael.Christensen@Sun.COM /* 10197697SMichael.Christensen@Sun.COM * Send the response 10207697SMichael.Christensen@Sun.COM */ 10217697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 10227697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 10237697SMichael.Christensen@Sun.COM return; 10247697SMichael.Christensen@Sun.COM } 10257697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' found, hdl: 0x%llx" DS_EOL, 10267697SMichael.Christensen@Sun.COM PORTID(port), req->svc_id, (u_longlong_t)svc->hdl); 10277697SMichael.Christensen@Sun.COM 10287697SMichael.Christensen@Sun.COM /* 10297697SMichael.Christensen@Sun.COM * A client sends out a reg req in order to force service providers to 10308172SMichael.Christensen@Sun.COM * initiate a reg req from their end (limitation in the protocol). We 10318172SMichael.Christensen@Sun.COM * expect the service provider to be in the inactive (DS_SVC_INACTIVE) 10328172SMichael.Christensen@Sun.COM * state. If the service provider has already sent out a reg req (the 10338172SMichael.Christensen@Sun.COM * state is DS_SVC_REG_PENDING) or has already handshaken (the 10348172SMichael.Christensen@Sun.COM * state is DS_SVC_ACTIVE), then we can simply ignore this reg 10358172SMichael.Christensen@Sun.COM * req. For any other state, we force an unregister before initiating 10368172SMichael.Christensen@Sun.COM * a reg req. 10377697SMichael.Christensen@Sun.COM */ 10387697SMichael.Christensen@Sun.COM 10397697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(req->svc_handle)) { 10408172SMichael.Christensen@Sun.COM switch (svc->state) { 10418172SMichael.Christensen@Sun.COM 10428172SMichael.Christensen@Sun.COM case DS_SVC_REG_PENDING: 10438172SMichael.Christensen@Sun.COM case DS_SVC_ACTIVE: 10448172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging " 10458172SMichael.Christensen@Sun.COM "client, state (%x)" DS_EOL, PORTID(port), 10468172SMichael.Christensen@Sun.COM req->svc_id, svc->state); 10478172SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 10488172SMichael.Christensen@Sun.COM return; 10498172SMichael.Christensen@Sun.COM 10508172SMichael.Christensen@Sun.COM case DS_SVC_INACTIVE: 10518172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging " 10528172SMichael.Christensen@Sun.COM "client" DS_EOL, PORTID(port), req->svc_id); 10538172SMichael.Christensen@Sun.COM break; 10548172SMichael.Christensen@Sun.COM 10558172SMichael.Christensen@Sun.COM default: 10568172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging " 10578172SMichael.Christensen@Sun.COM "client forced unreg, state (%x)" DS_EOL, 10588172SMichael.Christensen@Sun.COM PORTID(port), req->svc_id, svc->state); 10597697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, port); 10608172SMichael.Christensen@Sun.COM break; 10617697SMichael.Christensen@Sun.COM } 10627697SMichael.Christensen@Sun.COM (void) ds_svc_port_up(svc, port); 10637697SMichael.Christensen@Sun.COM (void) ds_svc_register_onport(svc, port); 10647697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 10657697SMichael.Christensen@Sun.COM return; 10667697SMichael.Christensen@Sun.COM } 10677697SMichael.Christensen@Sun.COM 10687697SMichael.Christensen@Sun.COM /* 10697697SMichael.Christensen@Sun.COM * Only remote service providers can initiate a registration. The 10707697SMichael.Christensen@Sun.COM * local sevice from here must be a client service. 10717697SMichael.Christensen@Sun.COM */ 10727697SMichael.Christensen@Sun.COM 10737697SMichael.Christensen@Sun.COM match = negotiate_version(svc->cap.nvers, svc->cap.vers, 10747697SMichael.Christensen@Sun.COM req->major_vers, &new_major, &new_minor); 10757697SMichael.Christensen@Sun.COM 10767697SMichael.Christensen@Sun.COM /* 10777697SMichael.Christensen@Sun.COM * Check version info. ACK only if the major numbers exactly 10787697SMichael.Christensen@Sun.COM * match. The service entity can retry with a new minor 10797697SMichael.Christensen@Sun.COM * based on the response sent as part of the NACK. 10807697SMichael.Christensen@Sun.COM */ 10817697SMichael.Christensen@Sun.COM if (match) { 10827697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' svc%d: state: %x " 10837697SMichael.Christensen@Sun.COM "svc_portid: %d" DS_EOL, PORTID(port), req->svc_id, 10847697SMichael.Christensen@Sun.COM (int)DS_HDL2IDX(svc->hdl), svc->state, 10857697SMichael.Christensen@Sun.COM (int)(svc->port == NULL ? -1 : PORTID(svc->port))); 10867697SMichael.Christensen@Sun.COM /* 10877697SMichael.Christensen@Sun.COM * If the current local service is already in use and 10887697SMichael.Christensen@Sun.COM * it's not on this port, clone it. 10897697SMichael.Christensen@Sun.COM */ 10907697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_INACTIVE) { 10917697SMichael.Christensen@Sun.COM if (svc->port != NULL && port == svc->port) { 10927697SMichael.Christensen@Sun.COM /* 10937697SMichael.Christensen@Sun.COM * Someone probably dropped an unreg req 10947697SMichael.Christensen@Sun.COM * somewhere. Force a local unreg. 10957697SMichael.Christensen@Sun.COM */ 10967697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, port); 10977697SMichael.Christensen@Sun.COM } else if (!DS_HDL_ISCLIENT(svc->hdl)) { 10987697SMichael.Christensen@Sun.COM /* 10997697SMichael.Christensen@Sun.COM * Can't clone a non-client (service provider) 11007697SMichael.Christensen@Sun.COM * handle. This is because old in-kernel 11017697SMichael.Christensen@Sun.COM * service providers can't deal with multiple 11027697SMichael.Christensen@Sun.COM * handles. 11037697SMichael.Christensen@Sun.COM */ 11047697SMichael.Christensen@Sun.COM goto do_reg_nack; 11057697SMichael.Christensen@Sun.COM } else { 11067697SMichael.Christensen@Sun.COM svc = ds_svc_clone(svc); 11077697SMichael.Christensen@Sun.COM } 11087697SMichael.Christensen@Sun.COM } 11097697SMichael.Christensen@Sun.COM svc->port = port; 11107697SMichael.Christensen@Sun.COM svc->svc_hdl = req->svc_handle; 11117697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 11127697SMichael.Christensen@Sun.COM 11137697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_ack_t); 11147697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 11157697SMichael.Christensen@Sun.COM 11167697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 11177697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_ACK; 11187697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_ack_t); 11197697SMichael.Christensen@Sun.COM 11207697SMichael.Christensen@Sun.COM ack = (ds_reg_ack_t *)(msg + DS_HDR_SZ); 11217697SMichael.Christensen@Sun.COM ack->svc_handle = req->svc_handle; 11227697SMichael.Christensen@Sun.COM ack->minor_vers = MIN(new_minor, req->minor_vers); 11237697SMichael.Christensen@Sun.COM 11247697SMichael.Christensen@Sun.COM 11257697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 11267697SMichael.Christensen@Sun.COM /* Call the registration callback */ 11277697SMichael.Christensen@Sun.COM version.major = req->major_vers; 11287697SMichael.Christensen@Sun.COM version.minor = ack->minor_vers; 11297697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &version, 11307697SMichael.Christensen@Sun.COM svc->hdl); 11317697SMichael.Christensen@Sun.COM } 11327697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 11337697SMichael.Christensen@Sun.COM 11347697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_ack>: '%s' minor=0x%04X" 11357697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, 11367697SMichael.Christensen@Sun.COM MIN(new_minor, req->minor_vers)); 11377697SMichael.Christensen@Sun.COM } else { 11387697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 11397697SMichael.Christensen@Sun.COM 11407697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_nack_t); 11417697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 11427697SMichael.Christensen@Sun.COM 11437697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 11447697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_NACK; 11457697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_nack_t); 11467697SMichael.Christensen@Sun.COM 11477697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ); 11487697SMichael.Christensen@Sun.COM nack->svc_handle = req->svc_handle; 11497697SMichael.Christensen@Sun.COM nack->result = DS_REG_VER_NACK; 11507697SMichael.Christensen@Sun.COM nack->major_vers = new_major; 11517697SMichael.Christensen@Sun.COM 11527697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s' major=0x%04X" 11537697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, new_major); 11547697SMichael.Christensen@Sun.COM } 11557697SMichael.Christensen@Sun.COM 11567697SMichael.Christensen@Sun.COM /* send message */ 11577697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 11587697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 11597697SMichael.Christensen@Sun.COM } 11607697SMichael.Christensen@Sun.COM 11617697SMichael.Christensen@Sun.COM static void 11627697SMichael.Christensen@Sun.COM ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len) 11637697SMichael.Christensen@Sun.COM { 11647697SMichael.Christensen@Sun.COM ds_reg_ack_t *ack; 11657697SMichael.Christensen@Sun.COM ds_ver_t *ver; 11667697SMichael.Christensen@Sun.COM ds_ver_t tmpver; 11677697SMichael.Christensen@Sun.COM ds_svc_t *svc; 11687697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_ack_t); 11697697SMichael.Christensen@Sun.COM 11707697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 11717697SMichael.Christensen@Sun.COM if (len != explen) { 11727697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid message " 11737697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 11747697SMichael.Christensen@Sun.COM explen); 11757697SMichael.Christensen@Sun.COM return; 11767697SMichael.Christensen@Sun.COM } 11777697SMichael.Christensen@Sun.COM 11787697SMichael.Christensen@Sun.COM ack = (ds_reg_ack_t *)(buf + DS_HDR_SZ); 11797697SMichael.Christensen@Sun.COM 11807697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 11817697SMichael.Christensen@Sun.COM 11827697SMichael.Christensen@Sun.COM /* 11837697SMichael.Christensen@Sun.COM * This searches for service based on how we generate handles 11847697SMichael.Christensen@Sun.COM * and so only works because this is a reg ack. 11857697SMichael.Christensen@Sun.COM */ 11867697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(ack->svc_handle) || 11877697SMichael.Christensen@Sun.COM (svc = ds_get_svc(ack->svc_handle)) == NULL) { 11887697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid handle 0x%llx" 11897697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle); 11907697SMichael.Christensen@Sun.COM goto done; 11917697SMichael.Christensen@Sun.COM } 11927697SMichael.Christensen@Sun.COM 11937697SMichael.Christensen@Sun.COM /* make sure the message makes sense */ 11947697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_REG_PENDING) { 11957697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid state (%d)" DS_EOL, 11967697SMichael.Christensen@Sun.COM PORTID(port), svc->state); 11977697SMichael.Christensen@Sun.COM goto done; 11987697SMichael.Christensen@Sun.COM } 11997697SMichael.Christensen@Sun.COM 12007697SMichael.Christensen@Sun.COM ver = &(svc->cap.vers[svc->ver_idx]); 12017697SMichael.Christensen@Sun.COM 12027697SMichael.Christensen@Sun.COM /* major version has been agreed upon */ 12037697SMichael.Christensen@Sun.COM svc->ver.major = ver->major; 12047697SMichael.Christensen@Sun.COM 12057697SMichael.Christensen@Sun.COM if (ack->minor_vers >= ver->minor) { 12067697SMichael.Christensen@Sun.COM /* 12077697SMichael.Christensen@Sun.COM * Use the minor version specified in the 12087697SMichael.Christensen@Sun.COM * original request. 12097697SMichael.Christensen@Sun.COM */ 12107697SMichael.Christensen@Sun.COM svc->ver.minor = ver->minor; 12117697SMichael.Christensen@Sun.COM } else { 12127697SMichael.Christensen@Sun.COM /* 12137697SMichael.Christensen@Sun.COM * Use the lower minor version returned in 12147697SMichael.Christensen@Sun.COM * the ack. By defninition, all lower minor 12157697SMichael.Christensen@Sun.COM * versions must be supported. 12167697SMichael.Christensen@Sun.COM */ 12177697SMichael.Christensen@Sun.COM svc->ver.minor = ack->minor_vers; 12187697SMichael.Christensen@Sun.COM } 12197697SMichael.Christensen@Sun.COM 12207697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 12217697SMichael.Christensen@Sun.COM svc->port = port; 12227697SMichael.Christensen@Sun.COM 12237697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_ack: '%s' v%d.%d ready, hdl=0x%llx" 12247697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, svc->ver.major, 12257697SMichael.Christensen@Sun.COM svc->ver.minor, (u_longlong_t)svc->hdl); 12267697SMichael.Christensen@Sun.COM 12277697SMichael.Christensen@Sun.COM /* notify the client that registration is complete */ 12287697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 12297697SMichael.Christensen@Sun.COM /* 12307697SMichael.Christensen@Sun.COM * Use a temporary version structure so that 12317697SMichael.Christensen@Sun.COM * the copy in the svc structure cannot be 12327697SMichael.Christensen@Sun.COM * modified by the client. 12337697SMichael.Christensen@Sun.COM */ 12347697SMichael.Christensen@Sun.COM tmpver.major = svc->ver.major; 12357697SMichael.Christensen@Sun.COM tmpver.minor = svc->ver.minor; 12367697SMichael.Christensen@Sun.COM 12377697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &tmpver, svc->hdl); 12387697SMichael.Christensen@Sun.COM } 12397697SMichael.Christensen@Sun.COM 12407697SMichael.Christensen@Sun.COM done: 12417697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 12427697SMichael.Christensen@Sun.COM } 12437697SMichael.Christensen@Sun.COM 12447697SMichael.Christensen@Sun.COM static void 12457697SMichael.Christensen@Sun.COM ds_try_next_port(ds_svc_t *svc, int portid) 12467697SMichael.Christensen@Sun.COM { 12477697SMichael.Christensen@Sun.COM ds_port_t *port; 12487697SMichael.Christensen@Sun.COM ds_portset_t totry; 12497697SMichael.Christensen@Sun.COM int i; 12507697SMichael.Christensen@Sun.COM 12517697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x %s" DS_EOL, portid, __func__); 12529535SMichael.Christensen@Sun.COM 12539535SMichael.Christensen@Sun.COM /* 12549535SMichael.Christensen@Sun.COM * Get the ports that haven't been tried yet and are available to try. 12559535SMichael.Christensen@Sun.COM */ 125610042SMichael.Christensen@Sun.COM DS_PORTSET_DUP(totry, svc->avail); 12579535SMichael.Christensen@Sun.COM for (i = 0; i < DS_MAX_PORTS; i++) { 125810042SMichael.Christensen@Sun.COM if (DS_PORT_IN_SET(svc->tried, i)) 125910042SMichael.Christensen@Sun.COM DS_PORTSET_DEL(totry, i); 12609535SMichael.Christensen@Sun.COM } 12619535SMichael.Christensen@Sun.COM 12627697SMichael.Christensen@Sun.COM if (DS_PORTSET_ISNULL(totry)) 12637697SMichael.Christensen@Sun.COM return; 12647697SMichael.Christensen@Sun.COM 12657697SMichael.Christensen@Sun.COM for (i = 0; i < DS_MAX_PORTS; i++, portid++) { 12667697SMichael.Christensen@Sun.COM if (portid >= DS_MAX_PORTS) { 12677697SMichael.Christensen@Sun.COM portid = 0; 12687697SMichael.Christensen@Sun.COM } 12697697SMichael.Christensen@Sun.COM 12707697SMichael.Christensen@Sun.COM /* 12717697SMichael.Christensen@Sun.COM * If the port is not in the available list, 12727697SMichael.Christensen@Sun.COM * it is not a candidate for registration. 12737697SMichael.Christensen@Sun.COM */ 12747697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(totry, portid)) { 12757697SMichael.Christensen@Sun.COM continue; 12767697SMichael.Christensen@Sun.COM } 12777697SMichael.Christensen@Sun.COM 12787697SMichael.Christensen@Sun.COM port = &ds_ports[portid]; 12797697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s trying ldc.id: %d" DS_EOL, 12807697SMichael.Christensen@Sun.COM portid, __func__, (uint_t)(port->ldc.id)); 12817697SMichael.Christensen@Sun.COM if (ds_send_reg_req(svc, port) == 0) { 12827697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send OK" DS_EOL, 12837697SMichael.Christensen@Sun.COM portid, __func__); 12847697SMichael.Christensen@Sun.COM /* register sent successfully */ 12857697SMichael.Christensen@Sun.COM break; 12867697SMichael.Christensen@Sun.COM } 12877697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send FAIL" DS_EOL, 12887697SMichael.Christensen@Sun.COM portid, __func__); 12897697SMichael.Christensen@Sun.COM 12907697SMichael.Christensen@Sun.COM /* reset the service to try the next port */ 12917697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 12927697SMichael.Christensen@Sun.COM } 12937697SMichael.Christensen@Sun.COM } 12947697SMichael.Christensen@Sun.COM 12957697SMichael.Christensen@Sun.COM static void 12967697SMichael.Christensen@Sun.COM ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len) 12977697SMichael.Christensen@Sun.COM { 12987697SMichael.Christensen@Sun.COM ds_reg_nack_t *nack; 12997697SMichael.Christensen@Sun.COM ds_svc_t *svc; 13007697SMichael.Christensen@Sun.COM int idx; 13017697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_nack_t); 13027697SMichael.Christensen@Sun.COM 13037697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 13047697SMichael.Christensen@Sun.COM if (len != explen) { 13057697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid message " 13067697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 13077697SMichael.Christensen@Sun.COM explen); 13087697SMichael.Christensen@Sun.COM return; 13097697SMichael.Christensen@Sun.COM } 13107697SMichael.Christensen@Sun.COM 13117697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(buf + DS_HDR_SZ); 13127697SMichael.Christensen@Sun.COM 13137697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 13147697SMichael.Christensen@Sun.COM 13157697SMichael.Christensen@Sun.COM /* 13167697SMichael.Christensen@Sun.COM * We expect a reg_nack for a client ping. 13177697SMichael.Christensen@Sun.COM */ 13187697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(nack->svc_handle)) { 13197697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: ping hdl: 0x%llx" 13207697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 13217697SMichael.Christensen@Sun.COM goto done; 13227697SMichael.Christensen@Sun.COM } 13237697SMichael.Christensen@Sun.COM 13247697SMichael.Christensen@Sun.COM /* 13257697SMichael.Christensen@Sun.COM * This searches for service based on how we generate handles 13267697SMichael.Christensen@Sun.COM * and so only works because this is a reg nack. 13277697SMichael.Christensen@Sun.COM */ 13287697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(nack->svc_handle)) == NULL) { 13297697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid handle 0x%llx" 13307697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 13317697SMichael.Christensen@Sun.COM goto done; 13327697SMichael.Christensen@Sun.COM } 13337697SMichael.Christensen@Sun.COM 13347697SMichael.Christensen@Sun.COM /* make sure the message makes sense */ 13357697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_REG_PENDING) { 133610042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' handle: 0x%llx " 133710042SMichael.Christensen@Sun.COM "invalid state (%d)" DS_EOL, PORTID(port), svc->cap.svc_id, 133810042SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle, svc->state); 13397697SMichael.Christensen@Sun.COM goto done; 13407697SMichael.Christensen@Sun.COM } 13417697SMichael.Christensen@Sun.COM 13427697SMichael.Christensen@Sun.COM if (nack->result == DS_REG_DUP) { 13437697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: duplicate registration " 13447697SMichael.Christensen@Sun.COM " for %s" DS_EOL, PORTID(port), svc->cap.svc_id); 13457697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 13467697SMichael.Christensen@Sun.COM goto done; 13477697SMichael.Christensen@Sun.COM } 13487697SMichael.Christensen@Sun.COM 13497697SMichael.Christensen@Sun.COM /* 13507697SMichael.Christensen@Sun.COM * A major version of zero indicates that the 13517697SMichael.Christensen@Sun.COM * service is not supported at all. 13527697SMichael.Christensen@Sun.COM */ 13537697SMichael.Christensen@Sun.COM if (nack->major_vers == 0) { 13547697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' not supported" 13557697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id); 13567697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 13577697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 13587697SMichael.Christensen@Sun.COM ds_try_next_port(svc, PORTID(port) + 1); 13597697SMichael.Christensen@Sun.COM goto done; 13607697SMichael.Christensen@Sun.COM } 13617697SMichael.Christensen@Sun.COM 13627697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' hdl=0x%llx, nack=%d.x" 13637697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, 13647697SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle, nack->major_vers); 13657697SMichael.Christensen@Sun.COM 13667697SMichael.Christensen@Sun.COM /* 13677697SMichael.Christensen@Sun.COM * Walk the version list for the service, looking for 13687697SMichael.Christensen@Sun.COM * a major version that is as close to the requested 13697697SMichael.Christensen@Sun.COM * major version as possible. 13707697SMichael.Christensen@Sun.COM */ 13717697SMichael.Christensen@Sun.COM for (idx = svc->ver_idx; idx < svc->cap.nvers; idx++) { 13727697SMichael.Christensen@Sun.COM if (svc->cap.vers[idx].major <= nack->major_vers) { 13737697SMichael.Christensen@Sun.COM /* found a version to try */ 13747697SMichael.Christensen@Sun.COM break; 13757697SMichael.Christensen@Sun.COM } 13767697SMichael.Christensen@Sun.COM } 13777697SMichael.Christensen@Sun.COM 13787697SMichael.Christensen@Sun.COM if (idx == svc->cap.nvers) { 13797697SMichael.Christensen@Sun.COM /* no supported version */ 13807697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: %s v%d.x not supported" 13817697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, nack->major_vers); 13827697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 13837697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 13847697SMichael.Christensen@Sun.COM ds_try_next_port(svc, PORTID(port) + 1); 13857697SMichael.Christensen@Sun.COM goto done; 13867697SMichael.Christensen@Sun.COM } 13877697SMichael.Christensen@Sun.COM 13887697SMichael.Christensen@Sun.COM /* start the handshake again */ 13897697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 13907697SMichael.Christensen@Sun.COM svc->ver_idx = idx; 13917697SMichael.Christensen@Sun.COM 13927697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 13937697SMichael.Christensen@Sun.COM 13947697SMichael.Christensen@Sun.COM done: 13957697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 13967697SMichael.Christensen@Sun.COM } 13977697SMichael.Christensen@Sun.COM 13987697SMichael.Christensen@Sun.COM static void 13997697SMichael.Christensen@Sun.COM ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len) 14007697SMichael.Christensen@Sun.COM { 14017697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 14027697SMichael.Christensen@Sun.COM ds_unreg_req_t *req; 14037697SMichael.Christensen@Sun.COM ds_unreg_ack_t *ack; 14047697SMichael.Christensen@Sun.COM ds_svc_t *svc; 14057697SMichael.Christensen@Sun.COM char *msg; 14067697SMichael.Christensen@Sun.COM size_t msglen; 14077697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_req_t); 14089916SMichael.Christensen@Sun.COM boolean_t is_up; 14097697SMichael.Christensen@Sun.COM 14107697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 14117697SMichael.Christensen@Sun.COM if (len != explen) { 14127697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_req: invalid message " 14137697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 14147697SMichael.Christensen@Sun.COM explen); 14157697SMichael.Christensen@Sun.COM return; 14167697SMichael.Christensen@Sun.COM } 14177697SMichael.Christensen@Sun.COM 14187697SMichael.Christensen@Sun.COM req = (ds_unreg_req_t *)(buf + DS_HDR_SZ); 14197697SMichael.Christensen@Sun.COM 14207697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 14217697SMichael.Christensen@Sun.COM 14227697SMichael.Christensen@Sun.COM /* lookup appropriate client or service */ 14237697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(req->svc_handle) || 14247697SMichael.Christensen@Sun.COM ((svc = ds_find_clnt_svc_by_hdl_port(req->svc_handle, port)) 14257697SMichael.Christensen@Sun.COM == NULL && ((svc = ds_get_svc(req->svc_handle)) == NULL || 14267697SMichael.Christensen@Sun.COM svc->port != port))) { 14279916SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 14289916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 14299916SMichael.Christensen@Sun.COM is_up = (port->ldc.state == LDC_UP); 14309916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 14319916SMichael.Christensen@Sun.COM if (!is_up) 14329916SMichael.Christensen@Sun.COM return; 143310042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: invalid handle 0x%llx" 14347697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)req->svc_handle); 14357697SMichael.Christensen@Sun.COM ds_send_unreg_nack(port, req->svc_handle); 14367697SMichael.Christensen@Sun.COM return; 14377697SMichael.Christensen@Sun.COM } 14387697SMichael.Christensen@Sun.COM 14397697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: '%s' handle 0x%llx" DS_EOL, 14407697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle); 14417697SMichael.Christensen@Sun.COM 14427697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 14437697SMichael.Christensen@Sun.COM 14447697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_ack>: '%s' hdl=0x%llx" DS_EOL, 14457697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle); 14467697SMichael.Christensen@Sun.COM 14477697SMichael.Christensen@Sun.COM ds_check_for_dup_services(svc); 14487697SMichael.Christensen@Sun.COM 14497697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 14507697SMichael.Christensen@Sun.COM 14517697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_ack_t); 14527697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 14537697SMichael.Christensen@Sun.COM 14547697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 14557697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG_ACK; 14567697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_ack_t); 14577697SMichael.Christensen@Sun.COM 14587697SMichael.Christensen@Sun.COM ack = (ds_unreg_ack_t *)(msg + DS_HDR_SZ); 14597697SMichael.Christensen@Sun.COM ack->svc_handle = req->svc_handle; 14607697SMichael.Christensen@Sun.COM 14617697SMichael.Christensen@Sun.COM /* send message */ 14627697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 14637697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 14647697SMichael.Christensen@Sun.COM 14657697SMichael.Christensen@Sun.COM } 14667697SMichael.Christensen@Sun.COM 14677697SMichael.Christensen@Sun.COM static void 14687697SMichael.Christensen@Sun.COM ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len) 14697697SMichael.Christensen@Sun.COM { 14707697SMichael.Christensen@Sun.COM ds_unreg_ack_t *ack; 14717697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_ack_t); 14727697SMichael.Christensen@Sun.COM 14737697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 14747697SMichael.Christensen@Sun.COM if (len != explen) { 14757697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_ack: invalid message " 14767697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 14777697SMichael.Christensen@Sun.COM explen); 14787697SMichael.Christensen@Sun.COM return; 14797697SMichael.Christensen@Sun.COM } 14807697SMichael.Christensen@Sun.COM 14817697SMichael.Christensen@Sun.COM ack = (ds_unreg_ack_t *)(buf + DS_HDR_SZ); 14827697SMichael.Christensen@Sun.COM 14837697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_ack: hdl=0x%llx" DS_EOL, 14847697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)ack->svc_handle); 14857697SMichael.Christensen@Sun.COM 14868894SMichael.Christensen@Sun.COM #ifdef DEBUG 14877697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 14887697SMichael.Christensen@Sun.COM 14897697SMichael.Christensen@Sun.COM /* 14907697SMichael.Christensen@Sun.COM * Since the unregister request was initiated locally, 14917697SMichael.Christensen@Sun.COM * the service structure has already been torn down. 14927697SMichael.Christensen@Sun.COM * Just perform a sanity check to make sure the message 14937697SMichael.Christensen@Sun.COM * is appropriate. 14947697SMichael.Christensen@Sun.COM */ 14957697SMichael.Christensen@Sun.COM if (ds_get_svc(ack->svc_handle) != NULL) { 14968894SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_ack: handle 0x%llx in use" 14977697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle); 14987697SMichael.Christensen@Sun.COM } 14997697SMichael.Christensen@Sun.COM 15007697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15018894SMichael.Christensen@Sun.COM #endif /* DEBUG */ 15027697SMichael.Christensen@Sun.COM } 15037697SMichael.Christensen@Sun.COM 15047697SMichael.Christensen@Sun.COM static void 15057697SMichael.Christensen@Sun.COM ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len) 15067697SMichael.Christensen@Sun.COM { 15077697SMichael.Christensen@Sun.COM ds_unreg_nack_t *nack; 15087697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_nack_t); 15097697SMichael.Christensen@Sun.COM 15107697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 15117697SMichael.Christensen@Sun.COM if (len != explen) { 15127697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_nack: invalid message " 15137697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 15147697SMichael.Christensen@Sun.COM explen); 15157697SMichael.Christensen@Sun.COM return; 15167697SMichael.Christensen@Sun.COM } 15177697SMichael.Christensen@Sun.COM 15187697SMichael.Christensen@Sun.COM nack = (ds_unreg_nack_t *)(buf + DS_HDR_SZ); 15197697SMichael.Christensen@Sun.COM 15207697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_nack: hdl=0x%llx" DS_EOL, 15217697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)nack->svc_handle); 15227697SMichael.Christensen@Sun.COM 15238894SMichael.Christensen@Sun.COM #ifdef DEBUG 15247697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 15257697SMichael.Christensen@Sun.COM 15267697SMichael.Christensen@Sun.COM /* 15277697SMichael.Christensen@Sun.COM * Since the unregister request was initiated locally, 15287697SMichael.Christensen@Sun.COM * the service structure has already been torn down. 15297697SMichael.Christensen@Sun.COM * Just perform a sanity check to make sure the message 15307697SMichael.Christensen@Sun.COM * is appropriate. 15317697SMichael.Christensen@Sun.COM */ 15327697SMichael.Christensen@Sun.COM if (ds_get_svc(nack->svc_handle) != NULL) { 15338894SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_nack: handle 0x%llx in use" 15347697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 15357697SMichael.Christensen@Sun.COM } 15367697SMichael.Christensen@Sun.COM 15377697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15388894SMichael.Christensen@Sun.COM #endif /* DEBUG */ 15397697SMichael.Christensen@Sun.COM } 15407697SMichael.Christensen@Sun.COM 15417697SMichael.Christensen@Sun.COM static void 15427697SMichael.Christensen@Sun.COM ds_handle_data(ds_port_t *port, caddr_t buf, size_t len) 15437697SMichael.Christensen@Sun.COM { 15447697SMichael.Christensen@Sun.COM ds_data_handle_t *data; 15457697SMichael.Christensen@Sun.COM ds_svc_t *svc; 15467697SMichael.Christensen@Sun.COM char *msg; 15477697SMichael.Christensen@Sun.COM int msgsz; 15487697SMichael.Christensen@Sun.COM int hdrsz; 15497697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_data_handle_t); 15507697SMichael.Christensen@Sun.COM 15517697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 15527697SMichael.Christensen@Sun.COM if (len < explen) { 15537697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data: invalid message length " 15547697SMichael.Christensen@Sun.COM "(%ld), expected at least %ld" DS_EOL, PORTID(port), len, 15557697SMichael.Christensen@Sun.COM explen); 15567697SMichael.Christensen@Sun.COM return; 15577697SMichael.Christensen@Sun.COM } 15587697SMichael.Christensen@Sun.COM 15597697SMichael.Christensen@Sun.COM data = (ds_data_handle_t *)(buf + DS_HDR_SZ); 15607697SMichael.Christensen@Sun.COM 15617697SMichael.Christensen@Sun.COM hdrsz = DS_HDR_SZ + sizeof (ds_data_handle_t); 15627697SMichael.Christensen@Sun.COM msgsz = len - hdrsz; 15637697SMichael.Christensen@Sun.COM 15647697SMichael.Christensen@Sun.COM /* strip off the header for the client */ 15657697SMichael.Christensen@Sun.COM msg = (msgsz) ? (buf + hdrsz) : NULL; 15667697SMichael.Christensen@Sun.COM 15677697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 15687697SMichael.Christensen@Sun.COM 15697697SMichael.Christensen@Sun.COM if ((svc = ds_find_clnt_svc_by_hdl_port(data->svc_handle, port)) 15707697SMichael.Christensen@Sun.COM == NULL) { 15717697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(data->svc_handle)) == NULL) { 15727697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15737697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data: invalid handle 0x%llx" 15747697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), 15757697SMichael.Christensen@Sun.COM (u_longlong_t)data->svc_handle); 15767697SMichael.Christensen@Sun.COM ds_send_data_nack(port, data->svc_handle); 15777697SMichael.Christensen@Sun.COM return; 15787697SMichael.Christensen@Sun.COM } 15797697SMichael.Christensen@Sun.COM } 15807697SMichael.Christensen@Sun.COM 15817697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15827697SMichael.Christensen@Sun.COM 15837697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <data: '%s' hdl=0x%llx" DS_EOL, 15847697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)svc->hdl); 15857697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msgsz); 15867697SMichael.Christensen@Sun.COM 15877697SMichael.Christensen@Sun.COM /* dispatch this message to the client */ 15887697SMichael.Christensen@Sun.COM (*svc->ops.ds_data_cb)(svc->ops.cb_arg, msg, msgsz); 15897697SMichael.Christensen@Sun.COM } 15907697SMichael.Christensen@Sun.COM 15917697SMichael.Christensen@Sun.COM static void 15927697SMichael.Christensen@Sun.COM ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len) 15937697SMichael.Christensen@Sun.COM { 15947697SMichael.Christensen@Sun.COM ds_svc_t *svc; 15957697SMichael.Christensen@Sun.COM ds_data_nack_t *nack; 15967697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_data_nack_t); 15977697SMichael.Christensen@Sun.COM 15987697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 15997697SMichael.Christensen@Sun.COM if (len != explen) { 16007697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data_nack: invalid message " 16017697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 16027697SMichael.Christensen@Sun.COM explen); 16037697SMichael.Christensen@Sun.COM return; 16047697SMichael.Christensen@Sun.COM } 16057697SMichael.Christensen@Sun.COM 16067697SMichael.Christensen@Sun.COM nack = (ds_data_nack_t *)(buf + DS_HDR_SZ); 16077697SMichael.Christensen@Sun.COM 16087697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack: hdl=0x%llx, result=0x%llx" 16097697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle, 16107697SMichael.Christensen@Sun.COM (u_longlong_t)nack->result); 16117697SMichael.Christensen@Sun.COM 16127697SMichael.Christensen@Sun.COM if (nack->result == DS_INV_HDL) { 16137697SMichael.Christensen@Sun.COM 16147697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 16157697SMichael.Christensen@Sun.COM 16167697SMichael.Christensen@Sun.COM if ((svc = ds_find_clnt_svc_by_hdl_port(nack->svc_handle, 16177697SMichael.Christensen@Sun.COM port)) == NULL) { 16187697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(nack->svc_handle)) == NULL) { 16197697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 16207697SMichael.Christensen@Sun.COM return; 16217697SMichael.Christensen@Sun.COM } 16227697SMichael.Christensen@Sun.COM } 16237697SMichael.Christensen@Sun.COM 16247697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data_nack: handle 0x%llx reported " 16257697SMichael.Christensen@Sun.COM " as invalid" DS_EOL, PORTID(port), 16267697SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle); 16277697SMichael.Christensen@Sun.COM 16287697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 16297697SMichael.Christensen@Sun.COM 16307697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 16317697SMichael.Christensen@Sun.COM } 16327697SMichael.Christensen@Sun.COM } 16337697SMichael.Christensen@Sun.COM 16347697SMichael.Christensen@Sun.COM /* Initialize the port */ 16357697SMichael.Christensen@Sun.COM void 16367697SMichael.Christensen@Sun.COM ds_send_init_req(ds_port_t *port) 16377697SMichael.Christensen@Sun.COM { 16387697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 16397697SMichael.Christensen@Sun.COM ds_init_req_t *init_req; 16407697SMichael.Christensen@Sun.COM size_t msglen; 16417697SMichael.Christensen@Sun.COM ds_ver_t *vers = &ds_vers[port->ver_idx]; 16427697SMichael.Christensen@Sun.COM 16437697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 16447697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_LDC_INIT) { 16457697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: invalid state: %d" 16467697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 16477697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 16487697SMichael.Christensen@Sun.COM return; 16497697SMichael.Christensen@Sun.COM } 16507697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 16517697SMichael.Christensen@Sun.COM 16527697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: req=v%d.%d" DS_EOL, 16537697SMichael.Christensen@Sun.COM PORTID(port), vers->major, vers->minor); 16547697SMichael.Christensen@Sun.COM 16557697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_init_req_t); 16567697SMichael.Christensen@Sun.COM hdr = DS_MALLOC(msglen); 16577697SMichael.Christensen@Sun.COM 16587697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_REQ; 16597697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_req_t); 16607697SMichael.Christensen@Sun.COM 16617697SMichael.Christensen@Sun.COM init_req = (ds_init_req_t *)((caddr_t)hdr + DS_HDR_SZ); 16627697SMichael.Christensen@Sun.COM init_req->major_vers = vers->major; 16637697SMichael.Christensen@Sun.COM init_req->minor_vers = vers->minor; 16647697SMichael.Christensen@Sun.COM 16657697SMichael.Christensen@Sun.COM if (ds_send_msg(port, (caddr_t)hdr, msglen) == 0) { 16667697SMichael.Christensen@Sun.COM /* 16677697SMichael.Christensen@Sun.COM * We've left the port state unlocked over the malloc/send, 16687697SMichael.Christensen@Sun.COM * make sure no one has changed the state under us before 16697697SMichael.Christensen@Sun.COM * we update the state. 16707697SMichael.Christensen@Sun.COM */ 16717697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 16727697SMichael.Christensen@Sun.COM if (port->state == DS_PORT_LDC_INIT) 16737697SMichael.Christensen@Sun.COM port->state = DS_PORT_INIT_REQ; 16747697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 16757697SMichael.Christensen@Sun.COM } 16767697SMichael.Christensen@Sun.COM DS_FREE(hdr, msglen); 16777697SMichael.Christensen@Sun.COM } 16787697SMichael.Christensen@Sun.COM 16797697SMichael.Christensen@Sun.COM static int 16807697SMichael.Christensen@Sun.COM ds_send_reg_req(ds_svc_t *svc, ds_port_t *port) 16817697SMichael.Christensen@Sun.COM { 16827697SMichael.Christensen@Sun.COM ds_ver_t *ver; 16837697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 16847697SMichael.Christensen@Sun.COM caddr_t msg; 16857697SMichael.Christensen@Sun.COM size_t msglen; 16867697SMichael.Christensen@Sun.COM ds_reg_req_t *req; 16877697SMichael.Christensen@Sun.COM size_t idlen; 16887697SMichael.Christensen@Sun.COM int rv; 16897697SMichael.Christensen@Sun.COM 16908172SMichael.Christensen@Sun.COM if ((svc->state != DS_SVC_INACTIVE) && 16918172SMichael.Christensen@Sun.COM ((svc->flags & DSSF_ISCLIENT) == 0)) { 16928172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: invalid svc state (%d) " 16938172SMichael.Christensen@Sun.COM "for svc '%s'" DS_EOL, PORTID(port), svc->state, 16948172SMichael.Christensen@Sun.COM svc->cap.svc_id); 16958172SMichael.Christensen@Sun.COM return (-1); 16968172SMichael.Christensen@Sun.COM } 16977697SMichael.Christensen@Sun.COM 16987697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 16997697SMichael.Christensen@Sun.COM 17007697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 17017697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 17027697SMichael.Christensen@Sun.COM /* can not send message */ 17037697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: channel %ld is not up" 17047697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 17057697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17067697SMichael.Christensen@Sun.COM return (-1); 17077697SMichael.Christensen@Sun.COM } 17087697SMichael.Christensen@Sun.COM 17097697SMichael.Christensen@Sun.COM /* make sure port is ready */ 17107697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 17117697SMichael.Christensen@Sun.COM /* can not send message */ 17127697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: port is not ready" 17137697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 17147697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17157697SMichael.Christensen@Sun.COM return (-1); 17167697SMichael.Christensen@Sun.COM } 17177697SMichael.Christensen@Sun.COM 17187697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17197697SMichael.Christensen@Sun.COM 17207697SMichael.Christensen@Sun.COM /* allocate the message buffer */ 17217697SMichael.Christensen@Sun.COM idlen = strlen(svc->cap.svc_id); 17227697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_reg_req_t) + idlen; 17237697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 17247697SMichael.Christensen@Sun.COM 17257697SMichael.Christensen@Sun.COM /* copy in the header data */ 17267697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 17277697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_REQ; 17287697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_req_t) + idlen; 17297697SMichael.Christensen@Sun.COM 17307697SMichael.Christensen@Sun.COM req = (ds_reg_req_t *)(msg + DS_HDR_SZ); 17317697SMichael.Christensen@Sun.COM req->svc_handle = svc->hdl; 17327697SMichael.Christensen@Sun.COM ver = &(svc->cap.vers[svc->ver_idx]); 17337697SMichael.Christensen@Sun.COM req->major_vers = ver->major; 17347697SMichael.Christensen@Sun.COM req->minor_vers = ver->minor; 17357697SMichael.Christensen@Sun.COM 17367697SMichael.Christensen@Sun.COM /* copy in the service id */ 17377697SMichael.Christensen@Sun.COM (void) memcpy(req->svc_id, svc->cap.svc_id, idlen + 1); 17387697SMichael.Christensen@Sun.COM 17397697SMichael.Christensen@Sun.COM /* send the message */ 17407697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: '%s' ver=%d.%d, hdl=0x%llx" 17417697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, ver->major, ver->minor, 17427697SMichael.Christensen@Sun.COM (u_longlong_t)svc->hdl); 17437697SMichael.Christensen@Sun.COM 17447697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 17457697SMichael.Christensen@Sun.COM svc->port = port; 17467697SMichael.Christensen@Sun.COM rv = -1; 17477697SMichael.Christensen@Sun.COM } else if ((svc->flags & DSSF_ISCLIENT) == 0) { 17487697SMichael.Christensen@Sun.COM svc->state = DS_SVC_REG_PENDING; 17497697SMichael.Christensen@Sun.COM } 17507697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 17517697SMichael.Christensen@Sun.COM 17527697SMichael.Christensen@Sun.COM return (rv); 17537697SMichael.Christensen@Sun.COM } 17547697SMichael.Christensen@Sun.COM 17557697SMichael.Christensen@Sun.COM /* 17567697SMichael.Christensen@Sun.COM * Keep around in case we want this later 17577697SMichael.Christensen@Sun.COM */ 17587697SMichael.Christensen@Sun.COM int 17597697SMichael.Christensen@Sun.COM ds_send_unreg_req(ds_svc_t *svc) 17607697SMichael.Christensen@Sun.COM { 17617697SMichael.Christensen@Sun.COM caddr_t msg; 17627697SMichael.Christensen@Sun.COM size_t msglen; 17637697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 17647697SMichael.Christensen@Sun.COM ds_unreg_req_t *req; 17657697SMichael.Christensen@Sun.COM ds_port_t *port = svc->port; 17667697SMichael.Christensen@Sun.COM int rv; 17677697SMichael.Christensen@Sun.COM 17687697SMichael.Christensen@Sun.COM if (port == NULL) { 17697697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "send_unreg_req: service '%s' not " 17707697SMichael.Christensen@Sun.COM "associated with a port" DS_EOL, svc->cap.svc_id); 17717697SMichael.Christensen@Sun.COM return (-1); 17727697SMichael.Christensen@Sun.COM } 17737697SMichael.Christensen@Sun.COM 17747697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 17757697SMichael.Christensen@Sun.COM 17767697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 17777697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 17787697SMichael.Christensen@Sun.COM /* can not send message */ 17797697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_req>: channel %ld is not up" 17807697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 17817697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17827697SMichael.Christensen@Sun.COM return (-1); 17837697SMichael.Christensen@Sun.COM } 17847697SMichael.Christensen@Sun.COM 17857697SMichael.Christensen@Sun.COM /* make sure port is ready */ 17867697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 17877697SMichael.Christensen@Sun.COM /* can not send message */ 17887697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_req>: port is not ready" DS_EOL, 17897697SMichael.Christensen@Sun.COM PORTID(port)); 17907697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17917697SMichael.Christensen@Sun.COM return (-1); 17927697SMichael.Christensen@Sun.COM } 17937697SMichael.Christensen@Sun.COM 17947697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17957697SMichael.Christensen@Sun.COM 17967697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_req_t); 17977697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 17987697SMichael.Christensen@Sun.COM 17997697SMichael.Christensen@Sun.COM /* copy in the header data */ 18007697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 18017697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG; 18027697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_req_t); 18037697SMichael.Christensen@Sun.COM 18047697SMichael.Christensen@Sun.COM req = (ds_unreg_req_t *)(msg + DS_HDR_SZ); 18057697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 18067697SMichael.Christensen@Sun.COM req->svc_handle = svc->svc_hdl; 18077697SMichael.Christensen@Sun.COM } else { 18087697SMichael.Christensen@Sun.COM req->svc_handle = svc->hdl; 18097697SMichael.Christensen@Sun.COM } 18107697SMichael.Christensen@Sun.COM 18117697SMichael.Christensen@Sun.COM /* send the message */ 18127697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_req>: '%s' hdl=0x%llx" DS_EOL, 18137697SMichael.Christensen@Sun.COM PORTID(port), (svc->cap.svc_id) ? svc->cap.svc_id : "NULL", 18147697SMichael.Christensen@Sun.COM (u_longlong_t)svc->hdl); 18157697SMichael.Christensen@Sun.COM 18167697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 18177697SMichael.Christensen@Sun.COM rv = -1; 18187697SMichael.Christensen@Sun.COM } 18197697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 18207697SMichael.Christensen@Sun.COM 18217697SMichael.Christensen@Sun.COM return (rv); 18227697SMichael.Christensen@Sun.COM } 18237697SMichael.Christensen@Sun.COM 18247697SMichael.Christensen@Sun.COM static void 18257697SMichael.Christensen@Sun.COM ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl) 18267697SMichael.Christensen@Sun.COM { 18277697SMichael.Christensen@Sun.COM caddr_t msg; 18287697SMichael.Christensen@Sun.COM size_t msglen; 18297697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 18307697SMichael.Christensen@Sun.COM ds_unreg_nack_t *nack; 18317697SMichael.Christensen@Sun.COM 18327697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 18337697SMichael.Christensen@Sun.COM 18347697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 18357697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 18367697SMichael.Christensen@Sun.COM /* can not send message */ 18377697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_nack>: channel %ld is not up" 18387697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 18397697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18407697SMichael.Christensen@Sun.COM return; 18417697SMichael.Christensen@Sun.COM } 18427697SMichael.Christensen@Sun.COM 18437697SMichael.Christensen@Sun.COM /* make sure port is ready */ 18447697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 18457697SMichael.Christensen@Sun.COM /* can not send message */ 18467697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_nack>: port is not ready" 18477697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 18487697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18497697SMichael.Christensen@Sun.COM return; 18507697SMichael.Christensen@Sun.COM } 18517697SMichael.Christensen@Sun.COM 18527697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18537697SMichael.Christensen@Sun.COM 18547697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_nack_t); 18557697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 18567697SMichael.Christensen@Sun.COM 18577697SMichael.Christensen@Sun.COM /* copy in the header data */ 18587697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 18597697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG_NACK; 18607697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_nack_t); 18617697SMichael.Christensen@Sun.COM 18627697SMichael.Christensen@Sun.COM nack = (ds_unreg_nack_t *)(msg + DS_HDR_SZ); 18637697SMichael.Christensen@Sun.COM nack->svc_handle = bad_hdl; 18647697SMichael.Christensen@Sun.COM 18657697SMichael.Christensen@Sun.COM /* send the message */ 18667697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_nack>: hdl=0x%llx" DS_EOL, 18677697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)bad_hdl); 18687697SMichael.Christensen@Sun.COM 18697697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 18707697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 18717697SMichael.Christensen@Sun.COM } 18727697SMichael.Christensen@Sun.COM 18737697SMichael.Christensen@Sun.COM static void 18747697SMichael.Christensen@Sun.COM ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl) 18757697SMichael.Christensen@Sun.COM { 18767697SMichael.Christensen@Sun.COM caddr_t msg; 18777697SMichael.Christensen@Sun.COM size_t msglen; 18787697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 18797697SMichael.Christensen@Sun.COM ds_data_nack_t *nack; 18807697SMichael.Christensen@Sun.COM 18817697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 18827697SMichael.Christensen@Sun.COM 18837697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 18847697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 18857697SMichael.Christensen@Sun.COM /* can not send message */ 18867697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: data_nack>: channel %ld is not up" 18877697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 18887697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18897697SMichael.Christensen@Sun.COM return; 18907697SMichael.Christensen@Sun.COM } 18917697SMichael.Christensen@Sun.COM 18927697SMichael.Christensen@Sun.COM /* make sure port is ready */ 18937697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 18947697SMichael.Christensen@Sun.COM /* can not send message */ 18957697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: data_nack>: port is not ready" DS_EOL, 18967697SMichael.Christensen@Sun.COM PORTID(port)); 18977697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18987697SMichael.Christensen@Sun.COM return; 18997697SMichael.Christensen@Sun.COM } 19007697SMichael.Christensen@Sun.COM 19017697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 19027697SMichael.Christensen@Sun.COM 19037697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_data_nack_t); 19047697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 19057697SMichael.Christensen@Sun.COM 19067697SMichael.Christensen@Sun.COM /* copy in the header data */ 19077697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 19087697SMichael.Christensen@Sun.COM hdr->msg_type = DS_NACK; 19097697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_data_nack_t); 19107697SMichael.Christensen@Sun.COM 19117697SMichael.Christensen@Sun.COM nack = (ds_data_nack_t *)(msg + DS_HDR_SZ); 19127697SMichael.Christensen@Sun.COM nack->svc_handle = bad_hdl; 19137697SMichael.Christensen@Sun.COM nack->result = DS_INV_HDL; 19147697SMichael.Christensen@Sun.COM 19157697SMichael.Christensen@Sun.COM /* send the message */ 19167697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack>: hdl=0x%llx" DS_EOL, 19177697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)bad_hdl); 19187697SMichael.Christensen@Sun.COM 19197697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 19207697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 19217697SMichael.Christensen@Sun.COM } 19227697SMichael.Christensen@Sun.COM 19237697SMichael.Christensen@Sun.COM /* END DS PROTOCOL SUPPORT FUNCTIONS */ 19247697SMichael.Christensen@Sun.COM 19257697SMichael.Christensen@Sun.COM #ifdef DEBUG 19267697SMichael.Christensen@Sun.COM 19277697SMichael.Christensen@Sun.COM #define BYTESPERLINE 8 19287697SMichael.Christensen@Sun.COM #define LINEWIDTH ((BYTESPERLINE * 3) + (BYTESPERLINE + 2) + 1) 19297697SMichael.Christensen@Sun.COM #define ASCIIOFFSET ((BYTESPERLINE * 3) + 2) 19307697SMichael.Christensen@Sun.COM #define ISPRINT(c) ((c >= ' ') && (c <= '~')) 19317697SMichael.Christensen@Sun.COM 19327697SMichael.Christensen@Sun.COM /* 19337697SMichael.Christensen@Sun.COM * Output a buffer formatted with a set number of bytes on 19347697SMichael.Christensen@Sun.COM * each line. Append each line with the ASCII equivalent of 19357697SMichael.Christensen@Sun.COM * each byte if it falls within the printable ASCII range, 19367697SMichael.Christensen@Sun.COM * and '.' otherwise. 19377697SMichael.Christensen@Sun.COM */ 19387697SMichael.Christensen@Sun.COM void 19397697SMichael.Christensen@Sun.COM ds_dump_msg(void *vbuf, size_t len) 19407697SMichael.Christensen@Sun.COM { 19417697SMichael.Christensen@Sun.COM int i, j; 19427697SMichael.Christensen@Sun.COM char *curr; 19437697SMichael.Christensen@Sun.COM char *aoff; 19447697SMichael.Christensen@Sun.COM char line[LINEWIDTH]; 19457697SMichael.Christensen@Sun.COM uint8_t *buf = vbuf; 19467697SMichael.Christensen@Sun.COM 19477697SMichael.Christensen@Sun.COM if (len > 128) 19487697SMichael.Christensen@Sun.COM len = 128; 19497697SMichael.Christensen@Sun.COM 19507697SMichael.Christensen@Sun.COM /* walk the buffer one line at a time */ 19517697SMichael.Christensen@Sun.COM for (i = 0; i < len; i += BYTESPERLINE) { 19527697SMichael.Christensen@Sun.COM 19537697SMichael.Christensen@Sun.COM bzero(line, LINEWIDTH); 19547697SMichael.Christensen@Sun.COM 19557697SMichael.Christensen@Sun.COM curr = line; 19567697SMichael.Christensen@Sun.COM aoff = line + ASCIIOFFSET; 19577697SMichael.Christensen@Sun.COM 19587697SMichael.Christensen@Sun.COM /* 19597697SMichael.Christensen@Sun.COM * Walk the bytes in the current line, storing 19607697SMichael.Christensen@Sun.COM * the hex value for the byte as well as the 19617697SMichael.Christensen@Sun.COM * ASCII representation in a temporary buffer. 19627697SMichael.Christensen@Sun.COM * All ASCII values are placed at the end of 19637697SMichael.Christensen@Sun.COM * the line. 19647697SMichael.Christensen@Sun.COM */ 19657697SMichael.Christensen@Sun.COM for (j = 0; (j < BYTESPERLINE) && ((i + j) < len); j++) { 19667697SMichael.Christensen@Sun.COM (void) sprintf(curr, " %02x", buf[i + j]); 19677697SMichael.Christensen@Sun.COM *aoff = (ISPRINT(buf[i + j])) ? buf[i + j] : '.'; 19687697SMichael.Christensen@Sun.COM curr += 3; 19697697SMichael.Christensen@Sun.COM aoff++; 19707697SMichael.Christensen@Sun.COM } 19717697SMichael.Christensen@Sun.COM 19727697SMichael.Christensen@Sun.COM /* 19737697SMichael.Christensen@Sun.COM * Fill in to the start of the ASCII translation 19747697SMichael.Christensen@Sun.COM * with spaces. This will only be necessary if 19757697SMichael.Christensen@Sun.COM * this is the last line and there are not enough 19767697SMichael.Christensen@Sun.COM * bytes to fill the whole line. 19777697SMichael.Christensen@Sun.COM */ 19787697SMichael.Christensen@Sun.COM while (curr != (line + ASCIIOFFSET)) 19797697SMichael.Christensen@Sun.COM *curr++ = ' '; 19807697SMichael.Christensen@Sun.COM 19817697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s" DS_EOL, line); 19827697SMichael.Christensen@Sun.COM } 19837697SMichael.Christensen@Sun.COM } 19847697SMichael.Christensen@Sun.COM #endif /* DEBUG */ 19857697SMichael.Christensen@Sun.COM 19867697SMichael.Christensen@Sun.COM 19877697SMichael.Christensen@Sun.COM /* 19887697SMichael.Christensen@Sun.COM * Walk the table of registered services, executing the specified callback 19897697SMichael.Christensen@Sun.COM * function for each service on a port. A non-zero return value from the 19907697SMichael.Christensen@Sun.COM * callback is used to terminate the walk, not to indicate an error. Returns 19917697SMichael.Christensen@Sun.COM * the index of the last service visited. 19927697SMichael.Christensen@Sun.COM */ 19937697SMichael.Christensen@Sun.COM int 19947697SMichael.Christensen@Sun.COM ds_walk_svcs(svc_cb_t svc_cb, void *arg) 19957697SMichael.Christensen@Sun.COM { 19967697SMichael.Christensen@Sun.COM int idx; 19977697SMichael.Christensen@Sun.COM ds_svc_t *svc; 19987697SMichael.Christensen@Sun.COM 19997697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 20007697SMichael.Christensen@Sun.COM 20017697SMichael.Christensen@Sun.COM /* walk every table entry */ 20027697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 20037697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 20047697SMichael.Christensen@Sun.COM 20057697SMichael.Christensen@Sun.COM /* execute the callback */ 20067697SMichael.Christensen@Sun.COM if ((*svc_cb)(svc, arg) != 0) 20077697SMichael.Christensen@Sun.COM break; 20087697SMichael.Christensen@Sun.COM } 20097697SMichael.Christensen@Sun.COM 20107697SMichael.Christensen@Sun.COM return (idx); 20117697SMichael.Christensen@Sun.COM } 20127697SMichael.Christensen@Sun.COM 20137697SMichael.Christensen@Sun.COM static int 20147697SMichael.Christensen@Sun.COM ds_svc_isfree(ds_svc_t *svc, void *arg) 20157697SMichael.Christensen@Sun.COM { 20167697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 20177697SMichael.Christensen@Sun.COM 20187697SMichael.Christensen@Sun.COM /* 20197697SMichael.Christensen@Sun.COM * Looking for a free service. This may be a NULL entry 20207697SMichael.Christensen@Sun.COM * in the table, or an unused structure that could be 20217697SMichael.Christensen@Sun.COM * reused. 20227697SMichael.Christensen@Sun.COM */ 20237697SMichael.Christensen@Sun.COM 20247697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 20257697SMichael.Christensen@Sun.COM /* yes, it is free */ 20267697SMichael.Christensen@Sun.COM return (1); 20277697SMichael.Christensen@Sun.COM } 20287697SMichael.Christensen@Sun.COM 20297697SMichael.Christensen@Sun.COM /* not a candidate */ 20307697SMichael.Christensen@Sun.COM return (0); 20317697SMichael.Christensen@Sun.COM } 20327697SMichael.Christensen@Sun.COM 20337697SMichael.Christensen@Sun.COM int 20347697SMichael.Christensen@Sun.COM ds_svc_ismatch(ds_svc_t *svc, void *arg) 20357697SMichael.Christensen@Sun.COM { 20367697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 20377697SMichael.Christensen@Sun.COM return (0); 20387697SMichael.Christensen@Sun.COM } 20397697SMichael.Christensen@Sun.COM 20407697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, arg) == 0 && 20417697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) == 0) { 20427697SMichael.Christensen@Sun.COM /* found a match */ 20437697SMichael.Christensen@Sun.COM return (1); 20447697SMichael.Christensen@Sun.COM } 20457697SMichael.Christensen@Sun.COM 20467697SMichael.Christensen@Sun.COM return (0); 20477697SMichael.Christensen@Sun.COM } 20487697SMichael.Christensen@Sun.COM 20497697SMichael.Christensen@Sun.COM int 20507697SMichael.Christensen@Sun.COM ds_svc_clnt_ismatch(ds_svc_t *svc, void *arg) 20517697SMichael.Christensen@Sun.COM { 20527697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 20537697SMichael.Christensen@Sun.COM return (0); 20547697SMichael.Christensen@Sun.COM } 20557697SMichael.Christensen@Sun.COM 20567697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, arg) == 0 && 20577697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) != 0) { 20587697SMichael.Christensen@Sun.COM /* found a match */ 20597697SMichael.Christensen@Sun.COM return (1); 20607697SMichael.Christensen@Sun.COM } 20617697SMichael.Christensen@Sun.COM 20627697SMichael.Christensen@Sun.COM return (0); 20637697SMichael.Christensen@Sun.COM } 20647697SMichael.Christensen@Sun.COM 20657697SMichael.Christensen@Sun.COM int 20667697SMichael.Christensen@Sun.COM ds_svc_free(ds_svc_t *svc, void *arg) 20677697SMichael.Christensen@Sun.COM { 20687697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 20697697SMichael.Christensen@Sun.COM 20707697SMichael.Christensen@Sun.COM if (svc == NULL) { 20717697SMichael.Christensen@Sun.COM return (0); 20727697SMichael.Christensen@Sun.COM } 20737697SMichael.Christensen@Sun.COM 20747697SMichael.Christensen@Sun.COM if (svc->cap.svc_id) { 20757697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1); 20767697SMichael.Christensen@Sun.COM svc->cap.svc_id = NULL; 20777697SMichael.Christensen@Sun.COM } 20787697SMichael.Christensen@Sun.COM 20797697SMichael.Christensen@Sun.COM if (svc->cap.vers) { 20807697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t)); 20817697SMichael.Christensen@Sun.COM svc->cap.vers = NULL; 20827697SMichael.Christensen@Sun.COM } 20837697SMichael.Christensen@Sun.COM 20847697SMichael.Christensen@Sun.COM DS_FREE(svc, sizeof (ds_svc_t)); 20857697SMichael.Christensen@Sun.COM 20867697SMichael.Christensen@Sun.COM return (0); 20877697SMichael.Christensen@Sun.COM } 20887697SMichael.Christensen@Sun.COM 208910042SMichael.Christensen@Sun.COM static void 209010042SMichael.Christensen@Sun.COM ds_set_svc_port_tried(char *svc_id, ds_port_t *port) 209110042SMichael.Christensen@Sun.COM { 209210042SMichael.Christensen@Sun.COM int idx; 209310042SMichael.Christensen@Sun.COM ds_svc_t *svc; 209410042SMichael.Christensen@Sun.COM 209510042SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 209610042SMichael.Christensen@Sun.COM 209710042SMichael.Christensen@Sun.COM /* walk every table entry */ 209810042SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 209910042SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 210010042SMichael.Christensen@Sun.COM if (!DS_SVC_ISFREE(svc) && (svc->flags & DSSF_ISCLIENT) != 0 && 210110042SMichael.Christensen@Sun.COM strcmp(svc_id, svc->cap.svc_id) == 0) 210210042SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->tried, PORTID(port)); 210310042SMichael.Christensen@Sun.COM } 210410042SMichael.Christensen@Sun.COM } 210510042SMichael.Christensen@Sun.COM 21067697SMichael.Christensen@Sun.COM static int 21077697SMichael.Christensen@Sun.COM ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port) 21087697SMichael.Christensen@Sun.COM { 21097697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 21107697SMichael.Christensen@Sun.COM 21117697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 21127697SMichael.Christensen@Sun.COM return (0); 21137697SMichael.Christensen@Sun.COM 21147697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(svc->avail, PORTID(port))) 21157697SMichael.Christensen@Sun.COM return (0); 21167697SMichael.Christensen@Sun.COM 211710042SMichael.Christensen@Sun.COM if (DS_PORT_IN_SET(svc->tried, PORTID(port))) 211810042SMichael.Christensen@Sun.COM return (0); 211910042SMichael.Christensen@Sun.COM 212010042SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) { 212110042SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->tried, PORTID(port)); 212210042SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_INACTIVE) 212310042SMichael.Christensen@Sun.COM return (0); 212410042SMichael.Christensen@Sun.COM } else { 212510042SMichael.Christensen@Sun.COM ds_set_svc_port_tried(svc->cap.svc_id, port); 212610042SMichael.Christensen@Sun.COM 212710042SMichael.Christensen@Sun.COM /* 212810042SMichael.Christensen@Sun.COM * Never send a client reg req to the SP. 212910042SMichael.Christensen@Sun.COM */ 213010042SMichael.Christensen@Sun.COM if (PORTID(port) == ds_sp_port_id) { 213110042SMichael.Christensen@Sun.COM return (0); 213210042SMichael.Christensen@Sun.COM } 213310042SMichael.Christensen@Sun.COM } 21347697SMichael.Christensen@Sun.COM 21357697SMichael.Christensen@Sun.COM if (ds_send_reg_req(svc, port) == 0) { 21367697SMichael.Christensen@Sun.COM /* register sent successfully */ 21377697SMichael.Christensen@Sun.COM return (1); 21387697SMichael.Christensen@Sun.COM } 21397697SMichael.Christensen@Sun.COM 21407697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) { 21417697SMichael.Christensen@Sun.COM /* reset the service */ 21427697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 21437697SMichael.Christensen@Sun.COM } 21447697SMichael.Christensen@Sun.COM return (0); 21457697SMichael.Christensen@Sun.COM } 21467697SMichael.Christensen@Sun.COM 214710042SMichael.Christensen@Sun.COM static int 214810042SMichael.Christensen@Sun.COM ds_svc_register_onport_walker(ds_svc_t *svc, void *arg) 214910042SMichael.Christensen@Sun.COM { 215010042SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 215110042SMichael.Christensen@Sun.COM 215210042SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 215310042SMichael.Christensen@Sun.COM return (0); 215410042SMichael.Christensen@Sun.COM 215510042SMichael.Christensen@Sun.COM (void) ds_svc_register_onport(svc, arg); 215610042SMichael.Christensen@Sun.COM return (0); 215710042SMichael.Christensen@Sun.COM } 215810042SMichael.Christensen@Sun.COM 21597697SMichael.Christensen@Sun.COM int 21607697SMichael.Christensen@Sun.COM ds_svc_register(ds_svc_t *svc, void *arg) 21617697SMichael.Christensen@Sun.COM { 21627697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 21637697SMichael.Christensen@Sun.COM ds_portset_t ports; 21647697SMichael.Christensen@Sun.COM ds_port_t *port; 21657697SMichael.Christensen@Sun.COM int idx; 21667697SMichael.Christensen@Sun.COM 21677697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 21687697SMichael.Christensen@Sun.COM 21697697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 21707697SMichael.Christensen@Sun.COM return (0); 21717697SMichael.Christensen@Sun.COM 21729535SMichael.Christensen@Sun.COM DS_PORTSET_DUP(ports, svc->avail); 21737697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 217410042SMichael.Christensen@Sun.COM for (idx = 0; idx < DS_MAX_PORTS; idx++) { 217510042SMichael.Christensen@Sun.COM if (DS_PORT_IN_SET(svc->tried, idx)) 217610042SMichael.Christensen@Sun.COM DS_PORTSET_DEL(ports, idx); 217710042SMichael.Christensen@Sun.COM } 21787697SMichael.Christensen@Sun.COM } else if (svc->state != DS_SVC_INACTIVE) 21797697SMichael.Christensen@Sun.COM return (0); 21807697SMichael.Christensen@Sun.COM 21817697SMichael.Christensen@Sun.COM if (DS_PORTSET_ISNULL(ports)) 21827697SMichael.Christensen@Sun.COM return (0); 21837697SMichael.Christensen@Sun.COM 21847697SMichael.Christensen@Sun.COM /* 21857697SMichael.Christensen@Sun.COM * Attempt to register the service. Start with the lowest 21867697SMichael.Christensen@Sun.COM * numbered port and continue until a registration message 21877697SMichael.Christensen@Sun.COM * is sent successfully, or there are no ports left to try. 21887697SMichael.Christensen@Sun.COM */ 21897697SMichael.Christensen@Sun.COM for (idx = 0; idx < DS_MAX_PORTS; idx++) { 21907697SMichael.Christensen@Sun.COM 21917697SMichael.Christensen@Sun.COM /* 21927697SMichael.Christensen@Sun.COM * If the port is not in the available list, 21937697SMichael.Christensen@Sun.COM * it is not a candidate for registration. 21947697SMichael.Christensen@Sun.COM */ 21957697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(ports, idx)) { 21967697SMichael.Christensen@Sun.COM continue; 21977697SMichael.Christensen@Sun.COM } 21987697SMichael.Christensen@Sun.COM 21997697SMichael.Christensen@Sun.COM port = &ds_ports[idx]; 22007697SMichael.Christensen@Sun.COM if (ds_svc_register_onport(svc, port)) { 22017697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 22027697SMichael.Christensen@Sun.COM break; 22037697SMichael.Christensen@Sun.COM } 22047697SMichael.Christensen@Sun.COM } 22057697SMichael.Christensen@Sun.COM 22067697SMichael.Christensen@Sun.COM return (0); 22077697SMichael.Christensen@Sun.COM } 22087697SMichael.Christensen@Sun.COM 22097697SMichael.Christensen@Sun.COM static int 22107697SMichael.Christensen@Sun.COM ds_svc_unregister(ds_svc_t *svc, void *arg) 22117697SMichael.Christensen@Sun.COM { 22127697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 22137697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 22147697SMichael.Christensen@Sun.COM 22157697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 22167697SMichael.Christensen@Sun.COM 22177697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 22187697SMichael.Christensen@Sun.COM return (0); 22197697SMichael.Christensen@Sun.COM } 22207697SMichael.Christensen@Sun.COM 22217697SMichael.Christensen@Sun.COM /* make sure the service is using this port */ 22227697SMichael.Christensen@Sun.COM if (svc->port != port) { 22237697SMichael.Christensen@Sun.COM return (0); 22247697SMichael.Christensen@Sun.COM } 22257697SMichael.Christensen@Sun.COM 22267697SMichael.Christensen@Sun.COM if (port) { 22277697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: svc_unreg: id='%s', ver=%d.%d, " 22287697SMichael.Christensen@Sun.COM " hdl=0x%09lx" DS_EOL, PORTID(port), svc->cap.svc_id, 22297697SMichael.Christensen@Sun.COM svc->ver.major, svc->ver.minor, svc->hdl); 22307697SMichael.Christensen@Sun.COM } else { 22317697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "port=NULL: svc_unreg: id='%s', ver=%d.%d, " 22327697SMichael.Christensen@Sun.COM " hdl=0x%09lx" DS_EOL, svc->cap.svc_id, svc->ver.major, 22337697SMichael.Christensen@Sun.COM svc->ver.minor, svc->hdl); 22347697SMichael.Christensen@Sun.COM } 22357697SMichael.Christensen@Sun.COM 22367697SMichael.Christensen@Sun.COM /* reset the service structure */ 22377697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 22387697SMichael.Christensen@Sun.COM 22397697SMichael.Christensen@Sun.COM /* call the client unregister callback */ 22407697SMichael.Christensen@Sun.COM if (svc->ops.ds_unreg_cb) { 22417697SMichael.Christensen@Sun.COM (*svc->ops.ds_unreg_cb)(svc->ops.cb_arg); 22427697SMichael.Christensen@Sun.COM } 22437697SMichael.Christensen@Sun.COM 22447697SMichael.Christensen@Sun.COM /* increment the count in the handle to prevent reuse */ 22457697SMichael.Christensen@Sun.COM hdl = DS_ALLOC_HDL(DS_HDL2IDX(svc->hdl), DS_HDL2COUNT(svc->hdl)); 22467697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(svc->hdl)) { 22477697SMichael.Christensen@Sun.COM DS_HDL_SET_ISCLIENT(hdl); 22487697SMichael.Christensen@Sun.COM } 22497697SMichael.Christensen@Sun.COM svc->hdl = hdl; 22507697SMichael.Christensen@Sun.COM 22517697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_UNREG_PENDING) { 22527697SMichael.Christensen@Sun.COM /* try to initiate a new registration */ 22537697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 22547697SMichael.Christensen@Sun.COM } 22557697SMichael.Christensen@Sun.COM 22567697SMichael.Christensen@Sun.COM return (0); 22577697SMichael.Christensen@Sun.COM } 22587697SMichael.Christensen@Sun.COM 22597697SMichael.Christensen@Sun.COM static int 22607697SMichael.Christensen@Sun.COM ds_svc_port_up(ds_svc_t *svc, void *arg) 22617697SMichael.Christensen@Sun.COM { 22627697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 22637697SMichael.Christensen@Sun.COM 22647697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 22657697SMichael.Christensen@Sun.COM /* nothing to do */ 22667697SMichael.Christensen@Sun.COM return (0); 22677697SMichael.Christensen@Sun.COM } 22687697SMichael.Christensen@Sun.COM 22697697SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->avail, port->id); 22707697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(svc->tried, port->id); 22717697SMichael.Christensen@Sun.COM 22727697SMichael.Christensen@Sun.COM return (0); 22737697SMichael.Christensen@Sun.COM } 22747697SMichael.Christensen@Sun.COM 227510042SMichael.Christensen@Sun.COM static void 227610042SMichael.Christensen@Sun.COM ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor) 227710042SMichael.Christensen@Sun.COM { 227810042SMichael.Christensen@Sun.COM boolean_t was_ready; 227910042SMichael.Christensen@Sun.COM 228010042SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 228110042SMichael.Christensen@Sun.COM was_ready = (port->state == DS_PORT_READY); 228210042SMichael.Christensen@Sun.COM if (!was_ready) { 228310042SMichael.Christensen@Sun.COM port->state = DS_PORT_READY; 228410042SMichael.Christensen@Sun.COM port->ver.major = major; 228510042SMichael.Christensen@Sun.COM port->ver.minor = minor; 228610042SMichael.Christensen@Sun.COM } 228710042SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 228810042SMichael.Christensen@Sun.COM 228910042SMichael.Christensen@Sun.COM if (!was_ready) { 229010042SMichael.Christensen@Sun.COM 229110042SMichael.Christensen@Sun.COM /* 229210042SMichael.Christensen@Sun.COM * The port came up, so update all the services 229310042SMichael.Christensen@Sun.COM * with this information. Follow that up with an 229410042SMichael.Christensen@Sun.COM * attempt to register any service that is not 229510042SMichael.Christensen@Sun.COM * already registered. 229610042SMichael.Christensen@Sun.COM */ 229710042SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 229810042SMichael.Christensen@Sun.COM 229910042SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_port_up, port); 230010042SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_register_onport_walker, port); 230110042SMichael.Christensen@Sun.COM 230210042SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 230310042SMichael.Christensen@Sun.COM } 230410042SMichael.Christensen@Sun.COM } 230510042SMichael.Christensen@Sun.COM 23067697SMichael.Christensen@Sun.COM ds_svc_t * 23077697SMichael.Christensen@Sun.COM ds_alloc_svc(void) 23087697SMichael.Christensen@Sun.COM { 23097697SMichael.Christensen@Sun.COM int idx; 23107697SMichael.Christensen@Sun.COM uint_t newmaxsvcs; 23117697SMichael.Christensen@Sun.COM ds_svc_t **newtbl; 23127697SMichael.Christensen@Sun.COM ds_svc_t *newsvc; 23137697SMichael.Christensen@Sun.COM 23147697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 23157697SMichael.Christensen@Sun.COM 23167697SMichael.Christensen@Sun.COM idx = ds_walk_svcs(ds_svc_isfree, NULL); 23177697SMichael.Christensen@Sun.COM 23187697SMichael.Christensen@Sun.COM if (idx != ds_svcs.maxsvcs) { 23197697SMichael.Christensen@Sun.COM goto found; 23207697SMichael.Christensen@Sun.COM } 23217697SMichael.Christensen@Sun.COM 23227697SMichael.Christensen@Sun.COM /* 23237697SMichael.Christensen@Sun.COM * There was no free space in the table. Grow 23247697SMichael.Christensen@Sun.COM * the table to double its current size. 23257697SMichael.Christensen@Sun.COM */ 23267697SMichael.Christensen@Sun.COM newmaxsvcs = ds_svcs.maxsvcs * 2; 23277697SMichael.Christensen@Sun.COM newtbl = DS_MALLOC(newmaxsvcs * sizeof (ds_svc_t *)); 23287697SMichael.Christensen@Sun.COM 23297697SMichael.Christensen@Sun.COM /* copy old table data to the new table */ 23307697SMichael.Christensen@Sun.COM (void) memcpy(newtbl, ds_svcs.tbl, 23317697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs * sizeof (ds_svc_t *)); 23327697SMichael.Christensen@Sun.COM 23337697SMichael.Christensen@Sun.COM /* clean up the old table */ 23347697SMichael.Christensen@Sun.COM DS_FREE(ds_svcs.tbl, ds_svcs.maxsvcs * sizeof (ds_svc_t *)); 23357697SMichael.Christensen@Sun.COM ds_svcs.tbl = newtbl; 23367697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs = newmaxsvcs; 23377697SMichael.Christensen@Sun.COM 23387697SMichael.Christensen@Sun.COM /* search for a free space again */ 23397697SMichael.Christensen@Sun.COM idx = ds_walk_svcs(ds_svc_isfree, NULL); 23407697SMichael.Christensen@Sun.COM 23417697SMichael.Christensen@Sun.COM /* the table is locked so should find a free slot */ 23427697SMichael.Christensen@Sun.COM ASSERT(idx != ds_svcs.maxsvcs); 23437697SMichael.Christensen@Sun.COM 23447697SMichael.Christensen@Sun.COM found: 23457697SMichael.Christensen@Sun.COM /* allocate a new svc structure if necessary */ 23467697SMichael.Christensen@Sun.COM if ((newsvc = ds_svcs.tbl[idx]) == NULL) { 23477697SMichael.Christensen@Sun.COM /* allocate a new service */ 23487697SMichael.Christensen@Sun.COM newsvc = DS_MALLOC(sizeof (ds_svc_t)); 23497697SMichael.Christensen@Sun.COM ds_svcs.tbl[idx] = newsvc; 23507697SMichael.Christensen@Sun.COM } 23517697SMichael.Christensen@Sun.COM 23527697SMichael.Christensen@Sun.COM /* fill in the handle */ 23537697SMichael.Christensen@Sun.COM newsvc->hdl = DS_ALLOC_HDL(idx, DS_HDL2COUNT(newsvc->hdl)); 23547697SMichael.Christensen@Sun.COM newsvc->state = DS_SVC_FREE; /* Mark as free temporarily */ 23557697SMichael.Christensen@Sun.COM 23567697SMichael.Christensen@Sun.COM return (newsvc); 23577697SMichael.Christensen@Sun.COM } 23587697SMichael.Christensen@Sun.COM 23597697SMichael.Christensen@Sun.COM static void 23607697SMichael.Christensen@Sun.COM ds_reset_svc(ds_svc_t *svc, ds_port_t *port) 23617697SMichael.Christensen@Sun.COM { 23627697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 23637697SMichael.Christensen@Sun.COM 23647697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_UNREG_PENDING) 23657697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 23667697SMichael.Christensen@Sun.COM svc->ver_idx = 0; 23677697SMichael.Christensen@Sun.COM svc->ver.major = 0; 23687697SMichael.Christensen@Sun.COM svc->ver.minor = 0; 23697697SMichael.Christensen@Sun.COM svc->port = NULL; 23707697SMichael.Christensen@Sun.COM if (port) { 23717697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(svc->avail, port->id); 23727697SMichael.Christensen@Sun.COM } 23737697SMichael.Christensen@Sun.COM } 23747697SMichael.Christensen@Sun.COM 23757697SMichael.Christensen@Sun.COM ds_svc_t * 23767697SMichael.Christensen@Sun.COM ds_get_svc(ds_svc_hdl_t hdl) 23777697SMichael.Christensen@Sun.COM { 23787697SMichael.Christensen@Sun.COM int idx; 23797697SMichael.Christensen@Sun.COM ds_svc_t *svc; 23807697SMichael.Christensen@Sun.COM 23817697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 23827697SMichael.Christensen@Sun.COM 23837697SMichael.Christensen@Sun.COM if (hdl == DS_INVALID_HDL) 23847697SMichael.Christensen@Sun.COM return (NULL); 23857697SMichael.Christensen@Sun.COM 23867697SMichael.Christensen@Sun.COM idx = DS_HDL2IDX(hdl); 23877697SMichael.Christensen@Sun.COM 23887697SMichael.Christensen@Sun.COM /* check if index is out of bounds */ 23897697SMichael.Christensen@Sun.COM if ((idx < 0) || (idx >= ds_svcs.maxsvcs)) 23907697SMichael.Christensen@Sun.COM return (NULL); 23917697SMichael.Christensen@Sun.COM 23927697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 23937697SMichael.Christensen@Sun.COM 23947697SMichael.Christensen@Sun.COM /* check for a valid service */ 23957697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 23967697SMichael.Christensen@Sun.COM return (NULL); 23977697SMichael.Christensen@Sun.COM 23987697SMichael.Christensen@Sun.COM /* make sure the handle is an exact match */ 23997697SMichael.Christensen@Sun.COM if (svc->hdl != hdl) 24007697SMichael.Christensen@Sun.COM return (NULL); 24017697SMichael.Christensen@Sun.COM 24027697SMichael.Christensen@Sun.COM return (svc); 24037697SMichael.Christensen@Sun.COM } 24047697SMichael.Christensen@Sun.COM 24057697SMichael.Christensen@Sun.COM static void 24067697SMichael.Christensen@Sun.COM ds_port_reset(ds_port_t *port) 24077697SMichael.Christensen@Sun.COM { 24087697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 24097697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 24107697SMichael.Christensen@Sun.COM 24117697SMichael.Christensen@Sun.COM /* connection went down, mark everything inactive */ 24127697SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_unregister, port); 24137697SMichael.Christensen@Sun.COM 24147697SMichael.Christensen@Sun.COM port->ver_idx = 0; 24157697SMichael.Christensen@Sun.COM port->ver.major = 0; 24167697SMichael.Christensen@Sun.COM port->ver.minor = 0; 24177697SMichael.Christensen@Sun.COM port->state = DS_PORT_LDC_INIT; 24187697SMichael.Christensen@Sun.COM } 24197697SMichael.Christensen@Sun.COM 24207697SMichael.Christensen@Sun.COM /* 24217697SMichael.Christensen@Sun.COM * Verify that a version array is sorted as expected for the 24227697SMichael.Christensen@Sun.COM * version negotiation to work correctly. 24237697SMichael.Christensen@Sun.COM */ 24247697SMichael.Christensen@Sun.COM ds_vers_check_t 24257697SMichael.Christensen@Sun.COM ds_vers_isvalid(ds_ver_t *vers, int nvers) 24267697SMichael.Christensen@Sun.COM { 24277697SMichael.Christensen@Sun.COM uint16_t curr_major; 24287697SMichael.Christensen@Sun.COM uint16_t curr_minor; 24297697SMichael.Christensen@Sun.COM int idx; 24307697SMichael.Christensen@Sun.COM 24317697SMichael.Christensen@Sun.COM curr_major = vers[0].major; 24327697SMichael.Christensen@Sun.COM curr_minor = vers[0].minor; 24337697SMichael.Christensen@Sun.COM 24347697SMichael.Christensen@Sun.COM /* 24357697SMichael.Christensen@Sun.COM * Walk the version array, verifying correct ordering. 24367697SMichael.Christensen@Sun.COM * The array must be sorted from highest supported 24377697SMichael.Christensen@Sun.COM * version to lowest supported version. 24387697SMichael.Christensen@Sun.COM */ 24397697SMichael.Christensen@Sun.COM for (idx = 0; idx < nvers; idx++) { 24407697SMichael.Christensen@Sun.COM if (vers[idx].major > curr_major) { 24417697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has " 24427697SMichael.Christensen@Sun.COM " increasing major versions" DS_EOL); 24437697SMichael.Christensen@Sun.COM return (DS_VERS_INCREASING_MAJOR_ERR); 24447697SMichael.Christensen@Sun.COM } 24457697SMichael.Christensen@Sun.COM 24467697SMichael.Christensen@Sun.COM if (vers[idx].major < curr_major) { 24477697SMichael.Christensen@Sun.COM curr_major = vers[idx].major; 24487697SMichael.Christensen@Sun.COM curr_minor = vers[idx].minor; 24497697SMichael.Christensen@Sun.COM continue; 24507697SMichael.Christensen@Sun.COM } 24517697SMichael.Christensen@Sun.COM 24527697SMichael.Christensen@Sun.COM if (vers[idx].minor > curr_minor) { 24537697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has " 24547697SMichael.Christensen@Sun.COM " increasing minor versions" DS_EOL); 24557697SMichael.Christensen@Sun.COM return (DS_VERS_INCREASING_MINOR_ERR); 24567697SMichael.Christensen@Sun.COM } 24577697SMichael.Christensen@Sun.COM 24587697SMichael.Christensen@Sun.COM curr_minor = vers[idx].minor; 24597697SMichael.Christensen@Sun.COM } 24607697SMichael.Christensen@Sun.COM 24617697SMichael.Christensen@Sun.COM return (DS_VERS_OK); 24627697SMichael.Christensen@Sun.COM } 24637697SMichael.Christensen@Sun.COM 24647697SMichael.Christensen@Sun.COM /* 24657697SMichael.Christensen@Sun.COM * Extended user capability init. 24667697SMichael.Christensen@Sun.COM */ 24677697SMichael.Christensen@Sun.COM int 24687697SMichael.Christensen@Sun.COM ds_ucap_init(ds_capability_t *cap, ds_clnt_ops_t *ops, uint32_t flags, 24697697SMichael.Christensen@Sun.COM int instance, ds_svc_hdl_t *hdlp) 24707697SMichael.Christensen@Sun.COM { 24717697SMichael.Christensen@Sun.COM ds_vers_check_t status; 24727697SMichael.Christensen@Sun.COM ds_svc_t *svc; 24737697SMichael.Christensen@Sun.COM int rv = 0; 24747697SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl, hdl; 24757697SMichael.Christensen@Sun.COM int is_loopback; 24767697SMichael.Christensen@Sun.COM int is_client; 24777697SMichael.Christensen@Sun.COM 24787697SMichael.Christensen@Sun.COM /* sanity check the args */ 24797697SMichael.Christensen@Sun.COM if ((cap == NULL) || (ops == NULL)) { 24807697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid arguments" DS_EOL, __func__); 24817697SMichael.Christensen@Sun.COM return (EINVAL); 24827697SMichael.Christensen@Sun.COM } 24837697SMichael.Christensen@Sun.COM 24847697SMichael.Christensen@Sun.COM /* sanity check the capability specifier */ 24857697SMichael.Christensen@Sun.COM if ((cap->svc_id == NULL) || (cap->vers == NULL) || (cap->nvers == 0)) { 24867697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid capability specifier" DS_EOL, 24877697SMichael.Christensen@Sun.COM __func__); 24887697SMichael.Christensen@Sun.COM return (EINVAL); 24897697SMichael.Christensen@Sun.COM } 24907697SMichael.Christensen@Sun.COM 24917697SMichael.Christensen@Sun.COM /* sanity check the version array */ 24927697SMichael.Christensen@Sun.COM if ((status = ds_vers_isvalid(cap->vers, cap->nvers)) != DS_VERS_OK) { 24937697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid capability version array " 24947697SMichael.Christensen@Sun.COM "for %s service: %s" DS_EOL, __func__, cap->svc_id, 24957697SMichael.Christensen@Sun.COM (status == DS_VERS_INCREASING_MAJOR_ERR) ? 24967697SMichael.Christensen@Sun.COM "increasing major versions" : 24977697SMichael.Christensen@Sun.COM "increasing minor versions"); 24987697SMichael.Christensen@Sun.COM return (EINVAL); 24997697SMichael.Christensen@Sun.COM } 25007697SMichael.Christensen@Sun.COM 25017697SMichael.Christensen@Sun.COM /* data and register callbacks are required */ 25027697SMichael.Christensen@Sun.COM if ((ops->ds_data_cb == NULL) || (ops->ds_reg_cb == NULL)) { 25037697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid ops specifier for %s service" 25047697SMichael.Christensen@Sun.COM DS_EOL, __func__, cap->svc_id); 25057697SMichael.Christensen@Sun.COM return (EINVAL); 25067697SMichael.Christensen@Sun.COM } 25077697SMichael.Christensen@Sun.COM 25087697SMichael.Christensen@Sun.COM flags &= DSSF_USERFLAGS; 25097697SMichael.Christensen@Sun.COM is_client = flags & DSSF_ISCLIENT; 25107697SMichael.Christensen@Sun.COM 25117697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: svc_id='%s', data_cb=0x%lx, cb_arg=0x%lx" 25127697SMichael.Christensen@Sun.COM DS_EOL, __func__, cap->svc_id, PTR_TO_LONG(ops->ds_data_cb), 25137697SMichael.Christensen@Sun.COM PTR_TO_LONG(ops->cb_arg)); 25147697SMichael.Christensen@Sun.COM 25157697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 25167697SMichael.Christensen@Sun.COM 25177697SMichael.Christensen@Sun.COM /* check if the service is already registered */ 25187697SMichael.Christensen@Sun.COM if (i_ds_hdl_lookup(cap->svc_id, is_client, NULL, 1) == 1) { 25197697SMichael.Christensen@Sun.COM /* already registered */ 25207697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "Service '%s'/%s already registered" DS_EOL, 25217697SMichael.Christensen@Sun.COM cap->svc_id, 25227697SMichael.Christensen@Sun.COM (flags & DSSF_ISCLIENT) ? "client" : "service"); 25237697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 25247697SMichael.Christensen@Sun.COM return (EALREADY); 25257697SMichael.Christensen@Sun.COM } 25267697SMichael.Christensen@Sun.COM 25277697SMichael.Christensen@Sun.COM svc = ds_alloc_svc(); 25287697SMichael.Christensen@Sun.COM if (is_client) { 25297697SMichael.Christensen@Sun.COM DS_HDL_SET_ISCLIENT(svc->hdl); 25307697SMichael.Christensen@Sun.COM } 25317697SMichael.Christensen@Sun.COM 25327697SMichael.Christensen@Sun.COM svc->state = DS_SVC_FREE; 25337697SMichael.Christensen@Sun.COM svc->svc_hdl = DS_BADHDL1; 25347697SMichael.Christensen@Sun.COM 25357697SMichael.Christensen@Sun.COM svc->flags = flags; 25367697SMichael.Christensen@Sun.COM svc->drvi = instance; 25377697SMichael.Christensen@Sun.COM svc->drv_psp = NULL; 25387697SMichael.Christensen@Sun.COM 25397697SMichael.Christensen@Sun.COM /* 25409242SMichael.Christensen@Sun.COM * Check for loopback. "pri" is a legacy service that assumes it 25419242SMichael.Christensen@Sun.COM * will never use loopback mode. 25427697SMichael.Christensen@Sun.COM */ 25439242SMichael.Christensen@Sun.COM if (strcmp(cap->svc_id, "pri") == 0) { 25449242SMichael.Christensen@Sun.COM is_loopback = 0; 25459242SMichael.Christensen@Sun.COM } else if (i_ds_hdl_lookup(cap->svc_id, is_client == 0, &lb_hdl, 1) 25469242SMichael.Christensen@Sun.COM == 1) { 25478172SMichael.Christensen@Sun.COM if ((rv = ds_loopback_set_svc(svc, cap, &lb_hdl)) != 0) { 25489242SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: ds_loopback_set_svc '%s' err " 25499242SMichael.Christensen@Sun.COM " (%d)" DS_EOL, __func__, cap->svc_id, rv); 25507697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 25517697SMichael.Christensen@Sun.COM return (rv); 25527697SMichael.Christensen@Sun.COM } 25537697SMichael.Christensen@Sun.COM is_loopback = 1; 25547697SMichael.Christensen@Sun.COM } else 25557697SMichael.Christensen@Sun.COM is_loopback = 0; 25567697SMichael.Christensen@Sun.COM 25577697SMichael.Christensen@Sun.COM /* copy over all the client information */ 25587697SMichael.Christensen@Sun.COM (void) memcpy(&svc->cap, cap, sizeof (ds_capability_t)); 25597697SMichael.Christensen@Sun.COM 25607697SMichael.Christensen@Sun.COM /* make a copy of the service name */ 25617697SMichael.Christensen@Sun.COM svc->cap.svc_id = ds_strdup(cap->svc_id); 25627697SMichael.Christensen@Sun.COM 25637697SMichael.Christensen@Sun.COM /* make a copy of the version array */ 25647697SMichael.Christensen@Sun.COM svc->cap.vers = DS_MALLOC(cap->nvers * sizeof (ds_ver_t)); 25657697SMichael.Christensen@Sun.COM (void) memcpy(svc->cap.vers, cap->vers, cap->nvers * sizeof (ds_ver_t)); 25667697SMichael.Christensen@Sun.COM 25677697SMichael.Christensen@Sun.COM /* copy the client ops vector */ 25687697SMichael.Christensen@Sun.COM (void) memcpy(&svc->ops, ops, sizeof (ds_clnt_ops_t)); 25697697SMichael.Christensen@Sun.COM 25707697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 25717697SMichael.Christensen@Sun.COM svc->ver_idx = 0; 25727697SMichael.Christensen@Sun.COM DS_PORTSET_DUP(svc->avail, ds_allports); 25737697SMichael.Christensen@Sun.COM DS_PORTSET_SETNULL(svc->tried); 25747697SMichael.Christensen@Sun.COM 25757697SMichael.Christensen@Sun.COM ds_svcs.nsvcs++; 25767697SMichael.Christensen@Sun.COM 25777697SMichael.Christensen@Sun.COM hdl = svc->hdl; 25787697SMichael.Christensen@Sun.COM 25797697SMichael.Christensen@Sun.COM /* 25807697SMichael.Christensen@Sun.COM * kludge to allow user callback code to get handle and user args. 25817697SMichael.Christensen@Sun.COM * Make sure the callback arg points to the svc structure. 25827697SMichael.Christensen@Sun.COM */ 25837697SMichael.Christensen@Sun.COM if ((flags & DSSF_ISUSER) != 0) { 25847697SMichael.Christensen@Sun.COM ds_cbarg_set_cookie(svc); 25857697SMichael.Christensen@Sun.COM } 25867697SMichael.Christensen@Sun.COM 25877697SMichael.Christensen@Sun.COM if (is_loopback) { 25887697SMichael.Christensen@Sun.COM ds_loopback_register(hdl); 25897697SMichael.Christensen@Sun.COM ds_loopback_register(lb_hdl); 25907697SMichael.Christensen@Sun.COM } 25917697SMichael.Christensen@Sun.COM 25927697SMichael.Christensen@Sun.COM /* 25937697SMichael.Christensen@Sun.COM * If this is a client or a non-loopback service provider, send 25947697SMichael.Christensen@Sun.COM * out register requests. 25957697SMichael.Christensen@Sun.COM */ 25967697SMichael.Christensen@Sun.COM if (!is_loopback || (flags & DSSF_ISCLIENT) != 0) 25977697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 25987697SMichael.Christensen@Sun.COM 25997697SMichael.Christensen@Sun.COM if (hdlp) { 26007697SMichael.Christensen@Sun.COM *hdlp = hdl; 26017697SMichael.Christensen@Sun.COM } 26027697SMichael.Christensen@Sun.COM 26037697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 26047697SMichael.Christensen@Sun.COM 26057697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: service '%s' assigned handle 0x%09lx" DS_EOL, 26067697SMichael.Christensen@Sun.COM __func__, svc->cap.svc_id, hdl); 26077697SMichael.Christensen@Sun.COM 26087697SMichael.Christensen@Sun.COM return (0); 26097697SMichael.Christensen@Sun.COM } 26107697SMichael.Christensen@Sun.COM 26117697SMichael.Christensen@Sun.COM /* 26127697SMichael.Christensen@Sun.COM * ds_cap_init interface for previous revision. 26137697SMichael.Christensen@Sun.COM */ 26147697SMichael.Christensen@Sun.COM int 26157697SMichael.Christensen@Sun.COM ds_cap_init(ds_capability_t *cap, ds_clnt_ops_t *ops) 26167697SMichael.Christensen@Sun.COM { 26177697SMichael.Christensen@Sun.COM return (ds_ucap_init(cap, ops, 0, DS_INVALID_INSTANCE, NULL)); 26187697SMichael.Christensen@Sun.COM } 26197697SMichael.Christensen@Sun.COM 26207697SMichael.Christensen@Sun.COM /* 26217697SMichael.Christensen@Sun.COM * Interface for ds_unreg_hdl in lds driver. 26227697SMichael.Christensen@Sun.COM */ 26237697SMichael.Christensen@Sun.COM int 26247697SMichael.Christensen@Sun.COM ds_unreg_hdl(ds_svc_hdl_t hdl) 26257697SMichael.Christensen@Sun.COM { 26267697SMichael.Christensen@Sun.COM ds_svc_t *svc; 26277697SMichael.Christensen@Sun.COM int is_loopback; 26287697SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl; 26297697SMichael.Christensen@Sun.COM 26307697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: hdl=0x%09lx" DS_EOL, __func__, hdl); 26317697SMichael.Christensen@Sun.COM 26327697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 26337697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 26347697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 26357697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: unknown hdl: 0x%llx" DS_EOL, __func__, 26367697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 26377697SMichael.Christensen@Sun.COM return (ENXIO); 26387697SMichael.Christensen@Sun.COM } 26397697SMichael.Christensen@Sun.COM 26407697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: svcid='%s', hdl=0x%llx" DS_EOL, __func__, 26417697SMichael.Christensen@Sun.COM svc->cap.svc_id, (u_longlong_t)svc->hdl); 26427697SMichael.Christensen@Sun.COM 26437697SMichael.Christensen@Sun.COM svc->state = DS_SVC_UNREG_PENDING; 26447697SMichael.Christensen@Sun.COM 26457697SMichael.Christensen@Sun.COM is_loopback = ((svc->flags & DSSF_LOOPBACK) != 0); 26467697SMichael.Christensen@Sun.COM lb_hdl = svc->svc_hdl; 26477697SMichael.Christensen@Sun.COM 26487697SMichael.Christensen@Sun.COM if (svc->port) { 26497697SMichael.Christensen@Sun.COM (void) ds_send_unreg_req(svc); 26507697SMichael.Christensen@Sun.COM } 26517697SMichael.Christensen@Sun.COM 26527697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 26537697SMichael.Christensen@Sun.COM 26547697SMichael.Christensen@Sun.COM ds_delete_svc_entry(svc); 26557697SMichael.Christensen@Sun.COM 26567697SMichael.Christensen@Sun.COM if (is_loopback) { 26577697SMichael.Christensen@Sun.COM ds_loopback_unregister(lb_hdl); 26587697SMichael.Christensen@Sun.COM } 26597697SMichael.Christensen@Sun.COM 26607697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 26617697SMichael.Christensen@Sun.COM 26627697SMichael.Christensen@Sun.COM return (0); 26637697SMichael.Christensen@Sun.COM } 26647697SMichael.Christensen@Sun.COM 26657697SMichael.Christensen@Sun.COM int 26667697SMichael.Christensen@Sun.COM ds_cap_fini(ds_capability_t *cap) 26677697SMichael.Christensen@Sun.COM { 26687697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 26697697SMichael.Christensen@Sun.COM int rv; 26707697SMichael.Christensen@Sun.COM uint_t nhdls = 0; 26717697SMichael.Christensen@Sun.COM 26727697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: '%s'" DS_EOL, __func__, cap->svc_id); 26737697SMichael.Christensen@Sun.COM if ((rv = ds_hdl_lookup(cap->svc_id, 0, &hdl, 1, &nhdls)) != 0) { 26747697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_hdl_lookup '%s' err (%d)" DS_EOL, 26757697SMichael.Christensen@Sun.COM __func__, cap->svc_id, rv); 26767697SMichael.Christensen@Sun.COM return (rv); 26777697SMichael.Christensen@Sun.COM } 26787697SMichael.Christensen@Sun.COM 26797697SMichael.Christensen@Sun.COM if (nhdls == 0) { 26807697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: no such service '%s'" DS_EOL, 26817697SMichael.Christensen@Sun.COM __func__, cap->svc_id); 26827697SMichael.Christensen@Sun.COM return (ENXIO); 26837697SMichael.Christensen@Sun.COM } 26847697SMichael.Christensen@Sun.COM 26857697SMichael.Christensen@Sun.COM if ((rv = ds_is_my_hdl(hdl, DS_INVALID_INSTANCE)) != 0) { 26867697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_is_my_handle err (%d)" DS_EOL, __func__, 26877697SMichael.Christensen@Sun.COM rv); 26887697SMichael.Christensen@Sun.COM return (rv); 26897697SMichael.Christensen@Sun.COM } 26907697SMichael.Christensen@Sun.COM 26917697SMichael.Christensen@Sun.COM if ((rv = ds_unreg_hdl(hdl)) != 0) { 26927697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_unreg_hdl err (%d)" DS_EOL, __func__, 26937697SMichael.Christensen@Sun.COM rv); 26947697SMichael.Christensen@Sun.COM return (rv); 26957697SMichael.Christensen@Sun.COM } 26967697SMichael.Christensen@Sun.COM 26977697SMichael.Christensen@Sun.COM return (0); 26987697SMichael.Christensen@Sun.COM } 26997697SMichael.Christensen@Sun.COM 27007697SMichael.Christensen@Sun.COM int 27017697SMichael.Christensen@Sun.COM ds_cap_send(ds_svc_hdl_t hdl, void *buf, size_t len) 27027697SMichael.Christensen@Sun.COM { 27037697SMichael.Christensen@Sun.COM int rv; 27047697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 27057697SMichael.Christensen@Sun.COM caddr_t msg; 27067697SMichael.Christensen@Sun.COM size_t msglen; 27077697SMichael.Christensen@Sun.COM size_t hdrlen; 27087697SMichael.Christensen@Sun.COM caddr_t payload; 27097697SMichael.Christensen@Sun.COM ds_svc_t *svc; 27107697SMichael.Christensen@Sun.COM ds_port_t *port; 27117697SMichael.Christensen@Sun.COM ds_data_handle_t *data; 27127697SMichael.Christensen@Sun.COM ds_svc_hdl_t svc_hdl; 27137697SMichael.Christensen@Sun.COM int is_client = 0; 27147697SMichael.Christensen@Sun.COM 27157697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: hdl: 0x%llx, buf: %lx, len: %ld" DS_EOL, __func__, 27167697SMichael.Christensen@Sun.COM (u_longlong_t)hdl, (ulong_t)buf, len); 27177697SMichael.Christensen@Sun.COM 27187697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 27197697SMichael.Christensen@Sun.COM 27207697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 27217697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "%s: invalid handle 0x%llx" DS_EOL, __func__, 27227697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 27237697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27247697SMichael.Christensen@Sun.COM return (ENXIO); 27257697SMichael.Christensen@Sun.COM } 27267697SMichael.Christensen@Sun.COM 27277697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_ACTIVE) { 27287697SMichael.Christensen@Sun.COM /* channel is up, but svc is not registered */ 27297697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: invalid service state 0x%x" DS_EOL, 27307697SMichael.Christensen@Sun.COM __func__, svc->state); 27317697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27327697SMichael.Christensen@Sun.COM return (ENOTCONN); 27337697SMichael.Christensen@Sun.COM } 27347697SMichael.Christensen@Sun.COM 27357697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_LOOPBACK) { 27367697SMichael.Christensen@Sun.COM hdl = svc->svc_hdl; 27377697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27387697SMichael.Christensen@Sun.COM ds_loopback_send(hdl, buf, len); 27397697SMichael.Christensen@Sun.COM return (0); 27407697SMichael.Christensen@Sun.COM } 27417697SMichael.Christensen@Sun.COM 27427697SMichael.Christensen@Sun.COM if ((port = svc->port) == NULL) { 27437697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: service '%s' not associated with a port" 27447697SMichael.Christensen@Sun.COM DS_EOL, __func__, svc->cap.svc_id); 27457697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27467697SMichael.Christensen@Sun.COM return (ECONNRESET); 27477697SMichael.Christensen@Sun.COM } 27487697SMichael.Christensen@Sun.COM 27497697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 27507697SMichael.Christensen@Sun.COM is_client = 1; 27517697SMichael.Christensen@Sun.COM svc_hdl = svc->svc_hdl; 27527697SMichael.Christensen@Sun.COM } 27537697SMichael.Christensen@Sun.COM 27547697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27557697SMichael.Christensen@Sun.COM 27567697SMichael.Christensen@Sun.COM /* check that the LDC channel is ready */ 27577697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 27587697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: LDC channel is not up" DS_EOL, __func__); 27597697SMichael.Christensen@Sun.COM return (ECONNRESET); 27607697SMichael.Christensen@Sun.COM } 27617697SMichael.Christensen@Sun.COM 27627697SMichael.Christensen@Sun.COM hdrlen = DS_HDR_SZ + sizeof (ds_data_handle_t); 27637697SMichael.Christensen@Sun.COM 27647697SMichael.Christensen@Sun.COM msg = DS_MALLOC(len + hdrlen); 27657697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 27667697SMichael.Christensen@Sun.COM payload = msg + hdrlen; 27677697SMichael.Christensen@Sun.COM msglen = len + hdrlen; 27687697SMichael.Christensen@Sun.COM 27697697SMichael.Christensen@Sun.COM hdr->payload_len = len + sizeof (ds_data_handle_t); 27707697SMichael.Christensen@Sun.COM hdr->msg_type = DS_DATA; 27717697SMichael.Christensen@Sun.COM 27727697SMichael.Christensen@Sun.COM data = (ds_data_handle_t *)(msg + DS_HDR_SZ); 27737697SMichael.Christensen@Sun.COM if (is_client) { 27747697SMichael.Christensen@Sun.COM data->svc_handle = svc_hdl; 27757697SMichael.Christensen@Sun.COM } else { 27767697SMichael.Christensen@Sun.COM data->svc_handle = hdl; 27777697SMichael.Christensen@Sun.COM } 27787697SMichael.Christensen@Sun.COM 27797697SMichael.Christensen@Sun.COM if ((buf != NULL) && (len != 0)) { 27807697SMichael.Christensen@Sun.COM (void) memcpy(payload, buf, len); 27817697SMichael.Christensen@Sun.COM } 27827697SMichael.Christensen@Sun.COM 27837697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data>: hdl=0x%llx, len=%ld, " 27847697SMichael.Christensen@Sun.COM " payload_len=%d" DS_EOL, PORTID(port), (u_longlong_t)svc->hdl, 27857697SMichael.Christensen@Sun.COM msglen, hdr->payload_len); 27867697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msglen); 27877697SMichael.Christensen@Sun.COM 27887697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 27897697SMichael.Christensen@Sun.COM rv = (rv == EIO) ? ECONNRESET : rv; 27907697SMichael.Christensen@Sun.COM } 27917697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 27927697SMichael.Christensen@Sun.COM 27937697SMichael.Christensen@Sun.COM return (rv); 27947697SMichael.Christensen@Sun.COM } 27957697SMichael.Christensen@Sun.COM 27967697SMichael.Christensen@Sun.COM void 27977697SMichael.Christensen@Sun.COM ds_port_common_init(ds_port_t *port) 27987697SMichael.Christensen@Sun.COM { 27997697SMichael.Christensen@Sun.COM int rv; 28007697SMichael.Christensen@Sun.COM 28017697SMichael.Christensen@Sun.COM if ((port->flags & DS_PORT_MUTEX_INITED) == 0) { 28027697SMichael.Christensen@Sun.COM mutex_init(&port->lock, NULL, MUTEX_DRIVER, NULL); 28037697SMichael.Christensen@Sun.COM mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL); 28047697SMichael.Christensen@Sun.COM mutex_init(&port->rcv_lock, NULL, MUTEX_DRIVER, NULL); 28057697SMichael.Christensen@Sun.COM port->flags |= DS_PORT_MUTEX_INITED; 28067697SMichael.Christensen@Sun.COM } 28077697SMichael.Christensen@Sun.COM 28087697SMichael.Christensen@Sun.COM port->state = DS_PORT_INIT; 28097697SMichael.Christensen@Sun.COM DS_PORTSET_ADD(ds_allports, port->id); 28107697SMichael.Christensen@Sun.COM 28117697SMichael.Christensen@Sun.COM ds_sys_port_init(port); 28127697SMichael.Christensen@Sun.COM 28137697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 28147697SMichael.Christensen@Sun.COM rv = ds_ldc_init(port); 28157697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 28167697SMichael.Christensen@Sun.COM 28177697SMichael.Christensen@Sun.COM /* 28187697SMichael.Christensen@Sun.COM * If LDC successfully init'ed, try to kick off protocol for this port. 28197697SMichael.Christensen@Sun.COM */ 28207697SMichael.Christensen@Sun.COM if (rv == 0) { 28217697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 28227697SMichael.Christensen@Sun.COM } 28237697SMichael.Christensen@Sun.COM } 28247697SMichael.Christensen@Sun.COM 28257697SMichael.Christensen@Sun.COM void 28269916SMichael.Christensen@Sun.COM ds_port_common_fini(ds_port_t *port) 28277697SMichael.Christensen@Sun.COM { 28289916SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 28299916SMichael.Christensen@Sun.COM 28307697SMichael.Christensen@Sun.COM port->state = DS_PORT_FREE; 28317697SMichael.Christensen@Sun.COM 28327697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(ds_allports, port->id); 28337697SMichael.Christensen@Sun.COM 28347697SMichael.Christensen@Sun.COM ds_sys_port_fini(port); 28357697SMichael.Christensen@Sun.COM } 28367697SMichael.Christensen@Sun.COM 28377697SMichael.Christensen@Sun.COM /* 28387697SMichael.Christensen@Sun.COM * Initialize table of registered service classes 28397697SMichael.Christensen@Sun.COM */ 28407697SMichael.Christensen@Sun.COM void 28417697SMichael.Christensen@Sun.COM ds_init_svcs_tbl(uint_t nentries) 28427697SMichael.Christensen@Sun.COM { 28437697SMichael.Christensen@Sun.COM int tblsz; 28447697SMichael.Christensen@Sun.COM 28457697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs = nentries; 28467697SMichael.Christensen@Sun.COM 28477697SMichael.Christensen@Sun.COM tblsz = ds_svcs.maxsvcs * sizeof (ds_svc_t *); 28487697SMichael.Christensen@Sun.COM ds_svcs.tbl = (ds_svc_t **)DS_MALLOC(tblsz); 28497697SMichael.Christensen@Sun.COM 28507697SMichael.Christensen@Sun.COM ds_svcs.nsvcs = 0; 28517697SMichael.Christensen@Sun.COM } 28527697SMichael.Christensen@Sun.COM 28537697SMichael.Christensen@Sun.COM /* 28547697SMichael.Christensen@Sun.COM * Find the max and min version supported. 28557697SMichael.Christensen@Sun.COM * Hacked from zeus workspace, support.c 28567697SMichael.Christensen@Sun.COM */ 28577697SMichael.Christensen@Sun.COM static void 28587697SMichael.Christensen@Sun.COM min_max_versions(int num_versions, ds_ver_t *sup_versionsp, 28597697SMichael.Christensen@Sun.COM uint16_t *min_major, uint16_t *max_major) 28607697SMichael.Christensen@Sun.COM { 28617697SMichael.Christensen@Sun.COM int i; 28627697SMichael.Christensen@Sun.COM 28637697SMichael.Christensen@Sun.COM *min_major = sup_versionsp[0].major; 28647697SMichael.Christensen@Sun.COM *max_major = *min_major; 28657697SMichael.Christensen@Sun.COM 28667697SMichael.Christensen@Sun.COM for (i = 1; i < num_versions; i++) { 28677697SMichael.Christensen@Sun.COM if (sup_versionsp[i].major < *min_major) 28687697SMichael.Christensen@Sun.COM *min_major = sup_versionsp[i].major; 28697697SMichael.Christensen@Sun.COM 28707697SMichael.Christensen@Sun.COM if (sup_versionsp[i].major > *max_major) 28717697SMichael.Christensen@Sun.COM *max_major = sup_versionsp[i].major; 28727697SMichael.Christensen@Sun.COM } 28737697SMichael.Christensen@Sun.COM } 28747697SMichael.Christensen@Sun.COM 28757697SMichael.Christensen@Sun.COM /* 28767697SMichael.Christensen@Sun.COM * Check whether the major and minor numbers requested by the peer can be 28777697SMichael.Christensen@Sun.COM * satisfied. If the requested major is supported, true is returned, and the 28787697SMichael.Christensen@Sun.COM * agreed minor is returned in new_minor. If the requested major is not 28797697SMichael.Christensen@Sun.COM * supported, the routine returns false, and the closest major is returned in 28807697SMichael.Christensen@Sun.COM * *new_major, upon which the peer should re-negotiate. The closest major is 28817697SMichael.Christensen@Sun.COM * the just lower that the requested major number. 28827697SMichael.Christensen@Sun.COM * 28837697SMichael.Christensen@Sun.COM * Hacked from zeus workspace, support.c 28847697SMichael.Christensen@Sun.COM */ 28857697SMichael.Christensen@Sun.COM boolean_t 28867697SMichael.Christensen@Sun.COM negotiate_version(int num_versions, ds_ver_t *sup_versionsp, 28877697SMichael.Christensen@Sun.COM uint16_t req_major, uint16_t *new_majorp, uint16_t *new_minorp) 28887697SMichael.Christensen@Sun.COM { 28897697SMichael.Christensen@Sun.COM int i; 28907697SMichael.Christensen@Sun.COM uint16_t major, lower_major; 28917697SMichael.Christensen@Sun.COM uint16_t min_major = 0, max_major; 28927697SMichael.Christensen@Sun.COM boolean_t found_match = B_FALSE; 28937697SMichael.Christensen@Sun.COM 28947697SMichael.Christensen@Sun.COM min_max_versions(num_versions, sup_versionsp, &min_major, &max_major); 28957697SMichael.Christensen@Sun.COM 28967697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "negotiate_version: req_major = %u, min = %u, max = %u" 28977697SMichael.Christensen@Sun.COM DS_EOL, req_major, min_major, max_major); 28987697SMichael.Christensen@Sun.COM 28997697SMichael.Christensen@Sun.COM /* 29007697SMichael.Christensen@Sun.COM * If the minimum version supported is greater than 29017697SMichael.Christensen@Sun.COM * the version requested, return the lowest version 29027697SMichael.Christensen@Sun.COM * supported 29037697SMichael.Christensen@Sun.COM */ 29047697SMichael.Christensen@Sun.COM if (min_major > req_major) { 29057697SMichael.Christensen@Sun.COM *new_majorp = min_major; 29067697SMichael.Christensen@Sun.COM return (B_FALSE); 29077697SMichael.Christensen@Sun.COM } 29087697SMichael.Christensen@Sun.COM 29097697SMichael.Christensen@Sun.COM /* 29107697SMichael.Christensen@Sun.COM * If the largest version supported is lower than 29117697SMichael.Christensen@Sun.COM * the version requested, return the largest version 29127697SMichael.Christensen@Sun.COM * supported 29137697SMichael.Christensen@Sun.COM */ 29147697SMichael.Christensen@Sun.COM if (max_major < req_major) { 29157697SMichael.Christensen@Sun.COM *new_majorp = max_major; 29167697SMichael.Christensen@Sun.COM return (B_FALSE); 29177697SMichael.Christensen@Sun.COM } 29187697SMichael.Christensen@Sun.COM 29197697SMichael.Christensen@Sun.COM /* 29207697SMichael.Christensen@Sun.COM * Now we know that the requested version lies between the 29217697SMichael.Christensen@Sun.COM * min and max versions supported. Check if the requested 29227697SMichael.Christensen@Sun.COM * major can be found in supported versions. 29237697SMichael.Christensen@Sun.COM */ 29247697SMichael.Christensen@Sun.COM lower_major = min_major; 29257697SMichael.Christensen@Sun.COM for (i = 0; i < num_versions; i++) { 29267697SMichael.Christensen@Sun.COM major = sup_versionsp[i].major; 29277697SMichael.Christensen@Sun.COM if (major == req_major) { 29287697SMichael.Christensen@Sun.COM found_match = B_TRUE; 29297697SMichael.Christensen@Sun.COM *new_majorp = req_major; 29307697SMichael.Christensen@Sun.COM *new_minorp = sup_versionsp[i].minor; 29317697SMichael.Christensen@Sun.COM break; 29327697SMichael.Christensen@Sun.COM } else { 29337697SMichael.Christensen@Sun.COM if ((major < req_major) && (major > lower_major)) 29347697SMichael.Christensen@Sun.COM lower_major = major; 29357697SMichael.Christensen@Sun.COM } 29367697SMichael.Christensen@Sun.COM } 29377697SMichael.Christensen@Sun.COM 29387697SMichael.Christensen@Sun.COM /* 29397697SMichael.Christensen@Sun.COM * If no match is found, return the closest available number 29407697SMichael.Christensen@Sun.COM */ 29417697SMichael.Christensen@Sun.COM if (!found_match) 29427697SMichael.Christensen@Sun.COM *new_majorp = lower_major; 29437697SMichael.Christensen@Sun.COM 29447697SMichael.Christensen@Sun.COM return (found_match); 29457697SMichael.Christensen@Sun.COM } 29467697SMichael.Christensen@Sun.COM 29477697SMichael.Christensen@Sun.COM /* 29487697SMichael.Christensen@Sun.COM * Specific errno's that are used by ds.c and ldc.c 29497697SMichael.Christensen@Sun.COM */ 29507697SMichael.Christensen@Sun.COM static struct { 29517697SMichael.Christensen@Sun.COM int ds_errno; 29527697SMichael.Christensen@Sun.COM char *estr; 29537697SMichael.Christensen@Sun.COM } ds_errno_to_str_tab[] = { 29547697SMichael.Christensen@Sun.COM { EIO, "I/O error" }, 29557697SMichael.Christensen@Sun.COM { ENXIO, "No such device or address" }, 29567697SMichael.Christensen@Sun.COM { EAGAIN, "Resource temporarily unavailable" }, 29577697SMichael.Christensen@Sun.COM { ENOMEM, "Not enough space" }, 29587697SMichael.Christensen@Sun.COM { EACCES, "Permission denied" }, 29597697SMichael.Christensen@Sun.COM { EFAULT, "Bad address" }, 29607697SMichael.Christensen@Sun.COM { EBUSY, "Device busy" }, 29617697SMichael.Christensen@Sun.COM { EINVAL, "Invalid argument" }, 29627697SMichael.Christensen@Sun.COM { ENOSPC, "No space left on device" }, 29637697SMichael.Christensen@Sun.COM { ENOMSG, "No message of desired type" }, 29647697SMichael.Christensen@Sun.COM #ifdef ECHRNG 29657697SMichael.Christensen@Sun.COM { ECHRNG, "Channel number out of range" }, 29667697SMichael.Christensen@Sun.COM #endif 29677697SMichael.Christensen@Sun.COM { ENOTSUP, "Operation not supported" }, 29687697SMichael.Christensen@Sun.COM { EMSGSIZE, "Message too long" }, 29697697SMichael.Christensen@Sun.COM { EADDRINUSE, "Address already in use" }, 29707697SMichael.Christensen@Sun.COM { ECONNRESET, "Connection reset by peer" }, 29717697SMichael.Christensen@Sun.COM { ENOBUFS, "No buffer space available" }, 29727697SMichael.Christensen@Sun.COM { ENOTCONN, "Socket is not connected" }, 29737697SMichael.Christensen@Sun.COM { ECONNREFUSED, "Connection refused" }, 29747697SMichael.Christensen@Sun.COM { EALREADY, "Operation already in progress" }, 29757697SMichael.Christensen@Sun.COM { 0, NULL }, 29767697SMichael.Christensen@Sun.COM }; 29777697SMichael.Christensen@Sun.COM 29787697SMichael.Christensen@Sun.COM char * 29797697SMichael.Christensen@Sun.COM ds_errno_to_str(int ds_errno, char *ebuf) 29807697SMichael.Christensen@Sun.COM { 29817697SMichael.Christensen@Sun.COM int i, en; 29827697SMichael.Christensen@Sun.COM 29837697SMichael.Christensen@Sun.COM for (i = 0; (en = ds_errno_to_str_tab[i].ds_errno) != 0; i++) { 29847697SMichael.Christensen@Sun.COM if (en == ds_errno) { 29857697SMichael.Christensen@Sun.COM (void) strcpy(ebuf, ds_errno_to_str_tab[i].estr); 29867697SMichael.Christensen@Sun.COM return (ebuf); 29877697SMichael.Christensen@Sun.COM } 29887697SMichael.Christensen@Sun.COM } 29897697SMichael.Christensen@Sun.COM 29907697SMichael.Christensen@Sun.COM (void) sprintf(ebuf, "ds_errno (%d)", ds_errno); 29917697SMichael.Christensen@Sun.COM return (ebuf); 29927697SMichael.Christensen@Sun.COM } 29937697SMichael.Christensen@Sun.COM 29947697SMichael.Christensen@Sun.COM static void 29957697SMichael.Christensen@Sun.COM ds_loopback_register(ds_svc_hdl_t hdl) 29967697SMichael.Christensen@Sun.COM { 29978172SMichael.Christensen@Sun.COM ds_ver_t ds_ver; 29987697SMichael.Christensen@Sun.COM ds_svc_t *svc; 29997697SMichael.Christensen@Sun.COM 30007697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 30017697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 30027697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30037697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 30047697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 30057697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30067697SMichael.Christensen@Sun.COM return; 30077697SMichael.Christensen@Sun.COM } 30088172SMichael.Christensen@Sun.COM 30097697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 30107697SMichael.Christensen@Sun.COM 30117697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 30127697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback regcb: hdl: 0x%llx" DS_EOL, 30137697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 30147697SMichael.Christensen@Sun.COM ds_ver.major = svc->ver.major; 30157697SMichael.Christensen@Sun.COM ds_ver.minor = svc->ver.minor; 30167697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &ds_ver, hdl); 30177697SMichael.Christensen@Sun.COM } 30187697SMichael.Christensen@Sun.COM } 30197697SMichael.Christensen@Sun.COM 30207697SMichael.Christensen@Sun.COM static void 30217697SMichael.Christensen@Sun.COM ds_loopback_unregister(ds_svc_hdl_t hdl) 30227697SMichael.Christensen@Sun.COM { 30237697SMichael.Christensen@Sun.COM ds_svc_t *svc; 30247697SMichael.Christensen@Sun.COM 30257697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 30267697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 30277697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 30287697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30297697SMichael.Christensen@Sun.COM return; 30307697SMichael.Christensen@Sun.COM } 30317697SMichael.Christensen@Sun.COM 30327697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 30337697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30347697SMichael.Christensen@Sun.COM 30357697SMichael.Christensen@Sun.COM svc->flags &= ~DSSF_LOOPBACK; 30367697SMichael.Christensen@Sun.COM svc->svc_hdl = DS_BADHDL2; 30378172SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 30387697SMichael.Christensen@Sun.COM 30397697SMichael.Christensen@Sun.COM if (svc->ops.ds_unreg_cb) { 30407697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback unregcb: hdl: 0x%llx" DS_EOL, 30417697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 30427697SMichael.Christensen@Sun.COM (*svc->ops.ds_unreg_cb)(svc->ops.cb_arg); 30437697SMichael.Christensen@Sun.COM } 30447697SMichael.Christensen@Sun.COM } 30457697SMichael.Christensen@Sun.COM 30467697SMichael.Christensen@Sun.COM static void 30477697SMichael.Christensen@Sun.COM ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen) 30487697SMichael.Christensen@Sun.COM { 30497697SMichael.Christensen@Sun.COM ds_svc_t *svc; 30507697SMichael.Christensen@Sun.COM 30517697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 30527697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 30537697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 30547697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 30557697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30567697SMichael.Christensen@Sun.COM return; 30577697SMichael.Christensen@Sun.COM } 30587697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 30597697SMichael.Christensen@Sun.COM 30607697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 30617697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30627697SMichael.Christensen@Sun.COM 30637697SMichael.Christensen@Sun.COM if (svc->ops.ds_data_cb) { 30647697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback datacb hdl: 0x%llx" DS_EOL, 30657697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 30667697SMichael.Christensen@Sun.COM (*svc->ops.ds_data_cb)(svc->ops.cb_arg, buf, buflen); 30677697SMichael.Christensen@Sun.COM } 30687697SMichael.Christensen@Sun.COM } 30697697SMichael.Christensen@Sun.COM 30707697SMichael.Christensen@Sun.COM static int 30718172SMichael.Christensen@Sun.COM ds_loopback_set_svc(ds_svc_t *svc, ds_capability_t *cap, ds_svc_hdl_t *lb_hdlp) 30727697SMichael.Christensen@Sun.COM { 30737697SMichael.Christensen@Sun.COM ds_svc_t *lb_svc; 30748172SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl = *lb_hdlp; 30758172SMichael.Christensen@Sun.COM int i; 30768172SMichael.Christensen@Sun.COM int match = 0; 30778172SMichael.Christensen@Sun.COM uint16_t new_major; 30788172SMichael.Christensen@Sun.COM uint16_t new_minor; 30797697SMichael.Christensen@Sun.COM 30807697SMichael.Christensen@Sun.COM if ((lb_svc = ds_get_svc(lb_hdl)) == NULL) { 30817697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback: hdl: 0x%llx invalid" DS_EOL, 30827697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)lb_hdl); 30837697SMichael.Christensen@Sun.COM return (ENXIO); 30847697SMichael.Christensen@Sun.COM } 30858172SMichael.Christensen@Sun.COM 30868172SMichael.Christensen@Sun.COM /* negotiate a version between loopback services, if possible */ 30878172SMichael.Christensen@Sun.COM for (i = 0; i < lb_svc->cap.nvers && match == 0; i++) { 30888172SMichael.Christensen@Sun.COM match = negotiate_version(cap->nvers, cap->vers, 30898172SMichael.Christensen@Sun.COM lb_svc->cap.vers[i].major, &new_major, &new_minor); 30908172SMichael.Christensen@Sun.COM } 30918172SMichael.Christensen@Sun.COM if (!match) { 30928172SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback version negotiate failed" 30938172SMichael.Christensen@Sun.COM DS_EOL, __func__); 30948172SMichael.Christensen@Sun.COM return (ENOTSUP); 30958172SMichael.Christensen@Sun.COM } 30967697SMichael.Christensen@Sun.COM if (lb_svc->state != DS_SVC_INACTIVE) { 30978172SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback active: hdl: 0x%llx" 30987697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)lb_hdl); 30997697SMichael.Christensen@Sun.COM if ((lb_svc->flags & DSSF_ISCLIENT) == 0) { 31007697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback busy hdl: 0x%llx" 31017697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)lb_hdl); 31027697SMichael.Christensen@Sun.COM return (EBUSY); 31037697SMichael.Christensen@Sun.COM } 31048172SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; /* prevent alloc'ing svc */ 31057697SMichael.Christensen@Sun.COM lb_svc = ds_svc_clone(lb_svc); 31067697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback clone: ohdl: 0x%llx " 31077697SMichael.Christensen@Sun.COM "nhdl: 0x%llx" DS_EOL, __func__, (u_longlong_t)lb_hdl, 31087697SMichael.Christensen@Sun.COM (u_longlong_t)lb_svc->hdl); 31098172SMichael.Christensen@Sun.COM *lb_hdlp = lb_svc->hdl; 31107697SMichael.Christensen@Sun.COM } 31117697SMichael.Christensen@Sun.COM 31127697SMichael.Christensen@Sun.COM svc->flags |= DSSF_LOOPBACK; 31137697SMichael.Christensen@Sun.COM svc->svc_hdl = lb_svc->hdl; 31147697SMichael.Christensen@Sun.COM svc->port = NULL; 31158172SMichael.Christensen@Sun.COM svc->ver.major = new_major; 31168172SMichael.Christensen@Sun.COM svc->ver.minor = new_minor; 31177697SMichael.Christensen@Sun.COM 31187697SMichael.Christensen@Sun.COM lb_svc->flags |= DSSF_LOOPBACK; 31197697SMichael.Christensen@Sun.COM lb_svc->svc_hdl = svc->hdl; 31207697SMichael.Christensen@Sun.COM lb_svc->port = NULL; 31218172SMichael.Christensen@Sun.COM lb_svc->ver.major = new_major; 31228172SMichael.Christensen@Sun.COM lb_svc->ver.minor = new_minor; 31237697SMichael.Christensen@Sun.COM 31247697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: setting loopback between: 0x%llx and 0x%llx" 31257697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)svc->hdl, 31267697SMichael.Christensen@Sun.COM (u_longlong_t)lb_svc->hdl); 31277697SMichael.Christensen@Sun.COM return (0); 31287697SMichael.Christensen@Sun.COM } 31297697SMichael.Christensen@Sun.COM 31307697SMichael.Christensen@Sun.COM static ds_svc_t * 31317697SMichael.Christensen@Sun.COM ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl, ds_port_t *port) 31327697SMichael.Christensen@Sun.COM { 31337697SMichael.Christensen@Sun.COM int idx; 31347697SMichael.Christensen@Sun.COM ds_svc_t *svc; 31357697SMichael.Christensen@Sun.COM 31367697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s looking up clnt hdl: 0x%llx" DS_EOL, 31377697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)hdl); 31387697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 31397697SMichael.Christensen@Sun.COM 31407697SMichael.Christensen@Sun.COM /* walk every table entry */ 31417697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 31427697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 31437697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 31447697SMichael.Christensen@Sun.COM continue; 31457697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != 0 && 31467697SMichael.Christensen@Sun.COM svc->svc_hdl == hdl && svc->port == port) { 31477697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s found clnt hdl " 31487697SMichael.Christensen@Sun.COM "0x%llx: svc%d" DS_EOL, PORTID(port), __func__, 31497697SMichael.Christensen@Sun.COM (u_longlong_t)hdl, (uint_t)DS_HDL2IDX(svc->hdl)); 31507697SMichael.Christensen@Sun.COM return (svc); 31517697SMichael.Christensen@Sun.COM } 31527697SMichael.Christensen@Sun.COM } 31537697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s clnt hdl: 0x%llx not found" DS_EOL, 31547697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)hdl); 31557697SMichael.Christensen@Sun.COM 31567697SMichael.Christensen@Sun.COM return (NULL); 31577697SMichael.Christensen@Sun.COM } 31587697SMichael.Christensen@Sun.COM 31597697SMichael.Christensen@Sun.COM static ds_svc_t * 31607697SMichael.Christensen@Sun.COM ds_svc_clone(ds_svc_t *svc) 31617697SMichael.Christensen@Sun.COM { 31627697SMichael.Christensen@Sun.COM ds_svc_t *newsvc; 31637697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 31647697SMichael.Christensen@Sun.COM 31657697SMichael.Christensen@Sun.COM ASSERT(svc->flags & DSSF_ISCLIENT); 31667697SMichael.Christensen@Sun.COM 31677697SMichael.Christensen@Sun.COM newsvc = ds_alloc_svc(); 31687697SMichael.Christensen@Sun.COM 31697697SMichael.Christensen@Sun.COM /* Can only clone clients for now */ 31707697SMichael.Christensen@Sun.COM hdl = newsvc->hdl | DS_HDL_ISCLIENT_BIT; 31717697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: cloning client: old hdl: 0x%llx new hdl: " 31727697SMichael.Christensen@Sun.COM "0x%llx" DS_EOL, __func__, (u_longlong_t)svc->hdl, 31737697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 31747697SMichael.Christensen@Sun.COM (void) memcpy(newsvc, svc, sizeof (ds_svc_t)); 31757697SMichael.Christensen@Sun.COM newsvc->hdl = hdl; 31767697SMichael.Christensen@Sun.COM newsvc->flags &= ~DSSF_LOOPBACK; 31777697SMichael.Christensen@Sun.COM newsvc->port = NULL; 31787697SMichael.Christensen@Sun.COM newsvc->svc_hdl = DS_BADHDL2; 31797697SMichael.Christensen@Sun.COM newsvc->cap.svc_id = ds_strdup(svc->cap.svc_id); 31807697SMichael.Christensen@Sun.COM newsvc->cap.vers = DS_MALLOC(svc->cap.nvers * sizeof (ds_ver_t)); 31817697SMichael.Christensen@Sun.COM (void) memcpy(newsvc->cap.vers, svc->cap.vers, 31827697SMichael.Christensen@Sun.COM svc->cap.nvers * sizeof (ds_ver_t)); 31837697SMichael.Christensen@Sun.COM 31847697SMichael.Christensen@Sun.COM /* 31857697SMichael.Christensen@Sun.COM * Kludge to allow lds driver user callbacks to get access to current 31867697SMichael.Christensen@Sun.COM * svc structure. Arg could be index to svc table or some other piece 31877697SMichael.Christensen@Sun.COM * of info to get to the svc table entry. 31887697SMichael.Christensen@Sun.COM */ 31897697SMichael.Christensen@Sun.COM if (newsvc->flags & DSSF_ISUSER) { 31907697SMichael.Christensen@Sun.COM newsvc->ops.cb_arg = (ds_cb_arg_t)(newsvc); 31917697SMichael.Christensen@Sun.COM } 31927697SMichael.Christensen@Sun.COM return (newsvc); 31937697SMichael.Christensen@Sun.COM } 31947697SMichael.Christensen@Sun.COM 31957697SMichael.Christensen@Sun.COM /* 31967697SMichael.Christensen@Sun.COM * Internal handle lookup function. 31977697SMichael.Christensen@Sun.COM */ 31987697SMichael.Christensen@Sun.COM static int 31997697SMichael.Christensen@Sun.COM i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 32007697SMichael.Christensen@Sun.COM uint_t maxhdls) 32017697SMichael.Christensen@Sun.COM { 32027697SMichael.Christensen@Sun.COM int idx; 32037697SMichael.Christensen@Sun.COM int nhdls = 0; 32047697SMichael.Christensen@Sun.COM ds_svc_t *svc; 32057697SMichael.Christensen@Sun.COM uint32_t client_flag = is_client ? DSSF_ISCLIENT : 0; 32067697SMichael.Christensen@Sun.COM 32077697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 32087697SMichael.Christensen@Sun.COM 32097697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs && nhdls < maxhdls; idx++) { 32107697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 32117697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 32127697SMichael.Christensen@Sun.COM continue; 32137697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, service) == 0 && 32147697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) == client_flag) { 32157697SMichael.Christensen@Sun.COM if (hdlp != NULL && nhdls < maxhdls) { 32167697SMichael.Christensen@Sun.COM hdlp[nhdls] = svc->hdl; 32177697SMichael.Christensen@Sun.COM nhdls++; 32187697SMichael.Christensen@Sun.COM } else { 32197697SMichael.Christensen@Sun.COM nhdls++; 32207697SMichael.Christensen@Sun.COM } 32217697SMichael.Christensen@Sun.COM } 32227697SMichael.Christensen@Sun.COM } 32237697SMichael.Christensen@Sun.COM return (nhdls); 32247697SMichael.Christensen@Sun.COM } 32257697SMichael.Christensen@Sun.COM 32267697SMichael.Christensen@Sun.COM /* 32277697SMichael.Christensen@Sun.COM * Interface for ds_hdl_lookup in lds driver. 32287697SMichael.Christensen@Sun.COM */ 32297697SMichael.Christensen@Sun.COM int 32307697SMichael.Christensen@Sun.COM ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 32317697SMichael.Christensen@Sun.COM uint_t maxhdls, uint_t *nhdlsp) 32327697SMichael.Christensen@Sun.COM { 32337697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 32347697SMichael.Christensen@Sun.COM *nhdlsp = i_ds_hdl_lookup(service, is_client, hdlp, maxhdls); 32357697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 32367697SMichael.Christensen@Sun.COM return (0); 32377697SMichael.Christensen@Sun.COM } 32387697SMichael.Christensen@Sun.COM 32397697SMichael.Christensen@Sun.COM /* 32407697SMichael.Christensen@Sun.COM * After an UNREG REQ, check if this is a client service with multiple 32417697SMichael.Christensen@Sun.COM * handles. If it is, then we can eliminate this entry. 32427697SMichael.Christensen@Sun.COM */ 32437697SMichael.Christensen@Sun.COM static void 32447697SMichael.Christensen@Sun.COM ds_check_for_dup_services(ds_svc_t *svc) 32457697SMichael.Christensen@Sun.COM { 32467697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != 0 && 32477697SMichael.Christensen@Sun.COM svc->state == DS_SVC_INACTIVE && 32487697SMichael.Christensen@Sun.COM i_ds_hdl_lookup(svc->cap.svc_id, 1, NULL, 2) == 2) { 32497697SMichael.Christensen@Sun.COM ds_delete_svc_entry(svc); 32507697SMichael.Christensen@Sun.COM } 32517697SMichael.Christensen@Sun.COM } 32527697SMichael.Christensen@Sun.COM 32537697SMichael.Christensen@Sun.COM static void 32547697SMichael.Christensen@Sun.COM ds_delete_svc_entry(ds_svc_t *svc) 32557697SMichael.Christensen@Sun.COM { 32567697SMichael.Christensen@Sun.COM ds_svc_hdl_t tmp_hdl; 32577697SMichael.Christensen@Sun.COM 32587697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 32597697SMichael.Christensen@Sun.COM 32607697SMichael.Christensen@Sun.COM /* 32617697SMichael.Christensen@Sun.COM * Clear out the structure, but do not deallocate the 32627697SMichael.Christensen@Sun.COM * memory. It can be reused for the next registration. 32637697SMichael.Christensen@Sun.COM */ 32647697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1); 32657697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t)); 32667697SMichael.Christensen@Sun.COM 32677697SMichael.Christensen@Sun.COM /* save the handle to prevent reuse */ 32687697SMichael.Christensen@Sun.COM tmp_hdl = svc->hdl; 32697697SMichael.Christensen@Sun.COM bzero((void *)svc, sizeof (ds_svc_t)); 32707697SMichael.Christensen@Sun.COM 32717697SMichael.Christensen@Sun.COM /* initialize for next use */ 32727697SMichael.Christensen@Sun.COM svc->hdl = tmp_hdl; 32737697SMichael.Christensen@Sun.COM svc->state = DS_SVC_FREE; 32747697SMichael.Christensen@Sun.COM 32757697SMichael.Christensen@Sun.COM ds_svcs.nsvcs--; 32767697SMichael.Christensen@Sun.COM } 3277