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