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