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