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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 * 24 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 25 */ 26 27 /* 28 * IPMP query interfaces (see PSARC/2002/615 and PSARC/2007/272). 29 */ 30 31 #include <assert.h> 32 #include <errno.h> 33 #include <libinetutil.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <sys/types.h> 38 39 #include "ipmp_impl.h" 40 #include "ipmp_mpathd.h" 41 #include "ipmp_query_impl.h" 42 43 static ipmp_ifinfo_t *ipmp_ifinfo_clone(ipmp_ifinfo_t *); 44 static ipmp_addrinfo_t *ipmp_addrinfo_clone(ipmp_addrinfo_t *); 45 static ipmp_addrlist_t *ipmp_addrlist_clone(ipmp_addrlist_t *); 46 static ipmp_grouplist_t *ipmp_grouplist_clone(ipmp_grouplist_t *); 47 static ipmp_groupinfo_t *ipmp_groupinfo_clone(ipmp_groupinfo_t *); 48 static ipmp_iflist_t *ipmp_iflist_create(uint_t, char (*)[LIFNAMSIZ]); 49 static void ipmp_freeiflist(ipmp_iflist_t *); 50 static ipmp_addrlist_t *ipmp_addrlist_create(uint_t, struct sockaddr_storage *); 51 static void ipmp_freeaddrlist(ipmp_addrlist_t *); 52 static ipmp_groupinfo_t *ipmp_snap_getgroupinfo(ipmp_snap_t *, const char *); 53 static ipmp_ifinfo_t *ipmp_snap_getifinfo(ipmp_snap_t *, const char *); 54 static ipmp_addrinfo_t *ipmp_snap_getaddrinfo(ipmp_snap_t *, const char *, 55 struct sockaddr_storage *); 56 static int ipmp_snap_take(ipmp_state_t *, ipmp_snap_t **); 57 static boolean_t ipmp_checktlv(ipmp_infotype_t, size_t, void *); 58 static int ipmp_querydone(ipmp_state_t *, int); 59 60 /* 61 * Using `statep', send a query request for `type' to in.mpathd, and if 62 * necessary wait until at least `endtp' for a response. Returns an IPMP 63 * error code. If successful, the caller may then read additional query 64 * information through ipmp_readinfo(), and must eventually call 65 * ipmp_querydone() to complete the query operation. Only one query may be 66 * outstanding on a given `statep' at a time. 67 */ 68 static int 69 ipmp_sendquery(ipmp_state_t *statep, ipmp_infotype_t type, const char *name, 70 const void *addr, struct timeval *endtp) 71 { 72 mi_query_t query; 73 mi_result_t result; 74 int retval; 75 76 query.miq_command = MI_QUERY; 77 query.miq_inforeq = type; 78 79 switch (type) { 80 case IPMP_ADDRINFO: 81 (void) strlcpy(query.miq_grname, name, LIFGRNAMSIZ); 82 query.miq_addr = *(struct sockaddr_storage *)addr; 83 break; 84 85 case IPMP_GROUPINFO: 86 (void) strlcpy(query.miq_grname, name, LIFGRNAMSIZ); 87 break; 88 89 case IPMP_IFINFO: 90 (void) strlcpy(query.miq_ifname, name, LIFNAMSIZ); 91 break; 92 93 case IPMP_GROUPLIST: 94 case IPMP_SNAP: 95 break; 96 97 default: 98 assert(0); 99 } 100 101 if (gettimeofday(endtp, NULL) == -1) 102 return (IPMP_FAILURE); 103 104 endtp->tv_sec += IPMP_REQTIMEOUT; 105 106 assert(statep->st_fd == -1); 107 retval = ipmp_connect(&statep->st_fd); 108 if (retval != IPMP_SUCCESS) 109 return (retval); 110 111 retval = ipmp_write(statep->st_fd, &query, sizeof (query)); 112 if (retval != IPMP_SUCCESS) 113 return (ipmp_querydone(statep, retval)); 114 115 retval = ipmp_read(statep->st_fd, &result, sizeof (result), endtp); 116 if (retval != IPMP_SUCCESS) 117 return (ipmp_querydone(statep, retval)); 118 119 if (result.me_mpathd_error != IPMP_SUCCESS) 120 return (ipmp_querydone(statep, result.me_mpathd_error)); 121 122 return (IPMP_SUCCESS); 123 } 124 125 /* 126 * Using `statep', read a query response of type `infotype' into a dynamically 127 * allocated buffer pointed to by `*infop', before the current time becomes 128 * `endtp'. Returns an IPMP error code. 129 */ 130 static int 131 ipmp_readinfo(ipmp_state_t *statep, ipmp_infotype_t infotype, void **infop, 132 const struct timeval *endtp) 133 { 134 int retval; 135 size_t len; 136 ipmp_infotype_t type; 137 138 retval = ipmp_readtlv(statep->st_fd, &type, &len, infop, endtp); 139 if (retval != IPMP_SUCCESS) 140 return (retval); 141 142 if (type != infotype || !ipmp_checktlv(type, len, *infop)) { 143 free(*infop); 144 return (IPMP_EPROTO); 145 } 146 147 return (IPMP_SUCCESS); 148 } 149 150 /* 151 * Using `statep', read in the remaining IPMP group information TLVs from 152 * in.mpathd into `grinfop' before the current time becomes `endtp'. Returns 153 * an IPMP error code. On failure, `grinfop' will have its original contents. 154 */ 155 static int 156 ipmp_readgroupinfo_lists(ipmp_state_t *statep, ipmp_groupinfo_t *grinfop, 157 const struct timeval *endtp) 158 { 159 int retval; 160 ipmp_iflist_t *iflistp; 161 ipmp_addrlist_t *adlistp; 162 163 retval = ipmp_readinfo(statep, IPMP_IFLIST, (void **)&iflistp, endtp); 164 if (retval != IPMP_SUCCESS) 165 return (retval); 166 167 retval = ipmp_readinfo(statep, IPMP_ADDRLIST, (void **)&adlistp, endtp); 168 if (retval != IPMP_SUCCESS) { 169 ipmp_freeiflist(iflistp); 170 return (retval); 171 } 172 173 grinfop->gr_iflistp = iflistp; 174 grinfop->gr_adlistp = adlistp; 175 return (IPMP_SUCCESS); 176 } 177 178 /* 179 * Using `statep', read in the remaining IPMP interface information TLVs from 180 * in.mpathd into `ifinfop' before the current time becomes `endtp'. Returns 181 * an IPMP error code. On failure, `ifinfop' will have its original contents. 182 */ 183 static int 184 ipmp_readifinfo_lists(ipmp_state_t *statep, ipmp_ifinfo_t *ifinfop, 185 const struct timeval *endtp) 186 { 187 int retval; 188 ipmp_addrlist_t *tlist4p, *tlist6p; 189 190 retval = ipmp_readinfo(statep, IPMP_ADDRLIST, (void **)&tlist4p, endtp); 191 if (retval != IPMP_SUCCESS) 192 return (retval); 193 194 retval = ipmp_readinfo(statep, IPMP_ADDRLIST, (void **)&tlist6p, endtp); 195 if (retval != IPMP_SUCCESS) { 196 ipmp_freeaddrlist(tlist4p); 197 return (retval); 198 } 199 200 ifinfop->if_targinfo4.it_targlistp = tlist4p; 201 ifinfop->if_targinfo6.it_targlistp = tlist6p; 202 return (IPMP_SUCCESS); 203 } 204 205 /* 206 * Complete the query operation started in ipmp_sendquery(). The interface is 207 * designed to be easy to use in the `return' statement of a function, and 208 * thus returns the passed in `retval' and preserves `errno'. 209 */ 210 static int 211 ipmp_querydone(ipmp_state_t *statep, int retval) 212 { 213 int error = errno; 214 215 (void) close(statep->st_fd); 216 statep->st_fd = -1; 217 errno = error; 218 return (retval); 219 } 220 221 /* 222 * Using `handle', get the group list and store the results in a dynamically 223 * allocated buffer pointed to by `*grlistpp'. Returns an IPMP error code. 224 */ 225 int 226 ipmp_getgrouplist(ipmp_handle_t handle, ipmp_grouplist_t **grlistpp) 227 { 228 ipmp_state_t *statep = handle; 229 struct timeval end; 230 int retval; 231 232 if (statep->st_snap != NULL) { 233 *grlistpp = ipmp_grouplist_clone(statep->st_snap->sn_grlistp); 234 return (*grlistpp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM); 235 } 236 237 retval = ipmp_sendquery(statep, IPMP_GROUPLIST, NULL, NULL, &end); 238 if (retval != IPMP_SUCCESS) 239 return (retval); 240 241 retval = ipmp_readinfo(statep, IPMP_GROUPLIST, (void **)grlistpp, &end); 242 return (ipmp_querydone(statep, retval)); 243 } 244 245 /* 246 * Free the group list pointed to by `grlistp'. 247 */ 248 void 249 ipmp_freegrouplist(ipmp_grouplist_t *grlistp) 250 { 251 free(grlistp); 252 } 253 254 /* 255 * Convert a ipmp_groupinfo_xfer_t used for communication with in.mpathd 256 * into a newly allocated ipmp_groupinfo_t. Free the ipmp_groupinfo_xfer_t, 257 * regardless of failure. 258 */ 259 static ipmp_groupinfo_t * 260 ipmp_convertgroupinfo(ipmp_groupinfo_xfer_t *grxferp) 261 { 262 ipmp_groupinfo_t *grinfop; 263 264 grinfop = calloc(1, sizeof (ipmp_groupinfo_t)); 265 if (grinfop != NULL) { 266 memcpy(grinfop->gr_name, grxferp->grx_name, 267 sizeof (grinfop->gr_name)); 268 grinfop->gr_sig = grxferp->grx_sig; 269 grinfop->gr_state = grxferp->grx_state; 270 memcpy(grinfop->gr_ifname, grxferp->grx_ifname, 271 sizeof (grinfop->gr_ifname)); 272 memcpy(grinfop->gr_m4ifname, grxferp->grx_m4ifname, 273 sizeof (grinfop->gr_m4ifname)); 274 memcpy(grinfop->gr_m6ifname, grxferp->grx_m6ifname, 275 sizeof (grinfop->gr_m6ifname)); 276 memcpy(grinfop->gr_bcifname, grxferp->grx_bcifname, 277 sizeof (grinfop->gr_bcifname)); 278 grinfop->gr_fdt = grxferp->grx_fdt; 279 } 280 281 free(grxferp); 282 283 return (grinfop); 284 } 285 /* 286 * Using `handle', get the group information associated with group `name' and 287 * store the results in a dynamically allocated buffer pointed to by 288 * `*grinfopp'. Returns an IPMP error code. 289 */ 290 int 291 ipmp_getgroupinfo(ipmp_handle_t handle, const char *name, 292 ipmp_groupinfo_t **grinfopp) 293 { 294 ipmp_state_t *statep = handle; 295 int retval; 296 struct timeval end; 297 ipmp_groupinfo_t *grinfop; 298 ipmp_groupinfo_xfer_t *grxferp; 299 300 if (statep->st_snap != NULL) { 301 grinfop = ipmp_snap_getgroupinfo(statep->st_snap, name); 302 if (grinfop == NULL) 303 return (IPMP_EUNKGROUP); 304 305 *grinfopp = ipmp_groupinfo_clone(grinfop); 306 return (*grinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM); 307 } 308 309 retval = ipmp_sendquery(statep, IPMP_GROUPINFO, name, NULL, &end); 310 if (retval != IPMP_SUCCESS) 311 return (retval); 312 313 retval = ipmp_readinfo(statep, IPMP_GROUPINFO, (void **)&grxferp, &end); 314 if (retval != IPMP_SUCCESS) 315 return (ipmp_querydone(statep, retval)); 316 317 *grinfopp = ipmp_convertgroupinfo(grxferp); 318 if (*grinfopp == NULL) 319 return (ipmp_querydone(statep, IPMP_ENOMEM)); 320 321 retval = ipmp_readgroupinfo_lists(statep, *grinfopp, &end); 322 if (retval != IPMP_SUCCESS) 323 free(*grinfopp); 324 325 return (ipmp_querydone(statep, retval)); 326 } 327 328 /* 329 * Free the group information pointed to by `grinfop'. 330 */ 331 void 332 ipmp_freegroupinfo(ipmp_groupinfo_t *grinfop) 333 { 334 ipmp_freeaddrlist(grinfop->gr_adlistp); 335 ipmp_freeiflist(grinfop->gr_iflistp); 336 free(grinfop); 337 } 338 339 /* 340 * Convert a ipmp_ifinfo_xfer_t used for communication with in.mpathd 341 * into a newly allocated ipmp_ifinfo_t. Free the ipmp_ifinfo_xfer_t, 342 * regardless of failure. 343 */ 344 static ipmp_ifinfo_t * 345 ipmp_convertifinfo(ipmp_ifinfo_xfer_t *ifxferp) 346 { 347 ipmp_ifinfo_t *ifinfop; 348 349 ifinfop = calloc(1, sizeof (ipmp_ifinfo_t)); 350 if (ifinfop != NULL) { 351 memcpy(ifinfop->if_name, ifxferp->ifx_name, 352 sizeof (ifinfop->if_name)); 353 memcpy(ifinfop->if_group, ifxferp->ifx_group, 354 sizeof (ifinfop->if_group)); 355 ifinfop->if_state = ifxferp->ifx_state; 356 ifinfop->if_type = ifxferp->ifx_type; 357 ifinfop->if_linkstate = ifxferp->ifx_linkstate; 358 ifinfop->if_probestate = ifxferp->ifx_probestate; 359 ifinfop->if_flags = ifxferp->ifx_flags; 360 memcpy(ifinfop->if_targinfo4.it_name, 361 ifxferp->ifx_targinfo4.itx_name, 362 sizeof (ifinfop->if_targinfo4.it_name)); 363 ifinfop->if_targinfo4.it_testaddr = 364 ifxferp->ifx_targinfo4.itx_testaddr; 365 ifinfop->if_targinfo4.it_targmode = 366 ifxferp->ifx_targinfo4.itx_targmode; 367 memcpy(ifinfop->if_targinfo6.it_name, 368 ifxferp->ifx_targinfo6.itx_name, 369 sizeof (ifinfop->if_targinfo6.it_name)); 370 ifinfop->if_targinfo6.it_testaddr = 371 ifxferp->ifx_targinfo6.itx_testaddr; 372 ifinfop->if_targinfo6.it_targmode = 373 ifxferp->ifx_targinfo6.itx_targmode; 374 } 375 376 free(ifxferp); 377 378 return (ifinfop); 379 } 380 381 /* 382 * Using `handle', get the interface information associated with interface 383 * `name' and store the results in a dynamically allocated buffer pointed to 384 * by `*ifinfopp'. Returns an IPMP error code. 385 */ 386 int 387 ipmp_getifinfo(ipmp_handle_t handle, const char *name, ipmp_ifinfo_t **ifinfopp) 388 { 389 ipmp_state_t *statep = handle; 390 ipmp_ifinfo_t *ifinfop; 391 ipmp_ifinfo_xfer_t *ifxferp; 392 int retval; 393 struct timeval end; 394 395 if (statep->st_snap != NULL) { 396 ifinfop = ipmp_snap_getifinfo(statep->st_snap, name); 397 if (ifinfop == NULL) 398 return (IPMP_EUNKIF); 399 400 *ifinfopp = ipmp_ifinfo_clone(ifinfop); 401 return (*ifinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM); 402 } 403 404 retval = ipmp_sendquery(statep, IPMP_IFINFO, name, NULL, &end); 405 if (retval != IPMP_SUCCESS) 406 return (retval); 407 408 retval = ipmp_readinfo(statep, IPMP_IFINFO, (void **)&ifxferp, &end); 409 if (retval != IPMP_SUCCESS) 410 return (ipmp_querydone(statep, retval)); 411 412 *ifinfopp = ipmp_convertifinfo(ifxferp); 413 if (*ifinfopp == NULL) 414 return (ipmp_querydone(statep, IPMP_ENOMEM)); 415 416 retval = ipmp_readifinfo_lists(statep, *ifinfopp, &end); 417 if (retval != IPMP_SUCCESS) 418 free(*ifinfopp); 419 420 return (ipmp_querydone(statep, retval)); 421 } 422 423 /* 424 * Free the interface information pointed to by `ifinfop'. 425 */ 426 void 427 ipmp_freeifinfo(ipmp_ifinfo_t *ifinfop) 428 { 429 ipmp_freeaddrlist(ifinfop->if_targinfo4.it_targlistp); 430 ipmp_freeaddrlist(ifinfop->if_targinfo6.it_targlistp); 431 free(ifinfop); 432 } 433 434 /* 435 * Using `handle', get the address information associated with address `addrp' 436 * on group `grname' and store the results in a dynamically allocated buffer 437 * pointed to by `*adinfopp'. Returns an IPMP error code. 438 */ 439 int 440 ipmp_getaddrinfo(ipmp_handle_t handle, const char *grname, 441 struct sockaddr_storage *addrp, ipmp_addrinfo_t **adinfopp) 442 { 443 ipmp_state_t *statep = handle; 444 ipmp_addrinfo_t *adinfop; 445 int retval; 446 struct timeval end; 447 448 if (statep->st_snap != NULL) { 449 adinfop = ipmp_snap_getaddrinfo(statep->st_snap, grname, addrp); 450 if (adinfop == NULL) 451 return (IPMP_EUNKADDR); 452 453 *adinfopp = ipmp_addrinfo_clone(adinfop); 454 return (*adinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM); 455 } 456 457 retval = ipmp_sendquery(statep, IPMP_ADDRINFO, grname, addrp, &end); 458 if (retval != IPMP_SUCCESS) 459 return (retval); 460 461 retval = ipmp_readinfo(statep, IPMP_ADDRINFO, (void **)adinfopp, &end); 462 return (ipmp_querydone(statep, retval)); 463 } 464 465 /* 466 * Free the address information pointed to by `adinfop'. 467 */ 468 void 469 ipmp_freeaddrinfo(ipmp_addrinfo_t *adinfop) 470 { 471 free(adinfop); 472 } 473 474 /* 475 * Check if `buf' has a NUL byte in its first `bufsize' bytes. 476 */ 477 static boolean_t 478 hasnulbyte(const char *buf, size_t bufsize) 479 { 480 while (bufsize-- > 0) { 481 if (buf[bufsize] == '\0') 482 return (B_TRUE); 483 } 484 return (B_FALSE); 485 } 486 487 /* 488 * Check that the TLV triplet named by `type', `len' and `value' is correctly 489 * formed. 490 */ 491 static boolean_t 492 ipmp_checktlv(ipmp_infotype_t type, size_t len, void *value) 493 { 494 ipmp_iflist_t *iflistp; 495 ipmp_ifinfo_xfer_t *ifxferp; 496 ipmp_grouplist_t *grlistp; 497 ipmp_groupinfo_xfer_t *grxferp; 498 ipmp_addrlist_t *adlistp; 499 unsigned int i; 500 501 switch (type) { 502 case IPMP_ADDRINFO: 503 if (len != sizeof (ipmp_addrinfo_t)) 504 return (B_FALSE); 505 break; 506 507 case IPMP_ADDRLIST: 508 adlistp = (ipmp_addrlist_t *)value; 509 if (len < IPMP_ADDRLIST_SIZE(0) || 510 len < IPMP_ADDRLIST_SIZE(adlistp->al_naddr)) 511 return (B_FALSE); 512 break; 513 514 case IPMP_IFLIST: 515 iflistp = (ipmp_iflist_t *)value; 516 if (len < IPMP_IFLIST_SIZE(0) || 517 len < IPMP_IFLIST_SIZE(iflistp->il_nif)) 518 return (B_FALSE); 519 520 for (i = 0; i < iflistp->il_nif; i++) 521 if (!hasnulbyte(iflistp->il_ifs[i], LIFNAMSIZ)) 522 return (B_FALSE); 523 break; 524 525 case IPMP_IFINFO: 526 ifxferp = (ipmp_ifinfo_xfer_t *)value; 527 if (len != sizeof (ipmp_ifinfo_xfer_t)) 528 return (B_FALSE); 529 530 if (!hasnulbyte(ifxferp->ifx_name, LIFNAMSIZ) || 531 !hasnulbyte(ifxferp->ifx_group, LIFGRNAMSIZ)) 532 return (B_FALSE); 533 break; 534 535 case IPMP_GROUPLIST: 536 grlistp = (ipmp_grouplist_t *)value; 537 if (len < IPMP_GROUPLIST_SIZE(0) || 538 len < IPMP_GROUPLIST_SIZE(grlistp->gl_ngroup)) 539 return (B_FALSE); 540 541 for (i = 0; i < grlistp->gl_ngroup; i++) 542 if (!hasnulbyte(grlistp->gl_groups[i], LIFGRNAMSIZ)) 543 return (B_FALSE); 544 break; 545 546 case IPMP_GROUPINFO: 547 grxferp = (ipmp_groupinfo_xfer_t *)value; 548 if (len != sizeof (ipmp_groupinfo_xfer_t)) 549 return (B_FALSE); 550 551 if (!hasnulbyte(grxferp->grx_name, LIFGRNAMSIZ)) 552 return (B_FALSE); 553 break; 554 555 case IPMP_ADDRCNT: 556 case IPMP_GROUPCNT: 557 case IPMP_IFCNT: 558 if (len != sizeof (uint32_t)) 559 return (B_FALSE); 560 break; 561 562 default: 563 return (B_FALSE); 564 } 565 566 return (B_TRUE); 567 } 568 569 /* 570 * Create a group list; arguments match ipmp_grouplist_t fields. Returns a 571 * pointer to the new group list on success, or NULL on failure. 572 */ 573 ipmp_grouplist_t * 574 ipmp_grouplist_create(uint64_t sig, unsigned int ngroup, 575 char (*groups)[LIFGRNAMSIZ]) 576 { 577 unsigned int i; 578 ipmp_grouplist_t *grlistp; 579 580 grlistp = malloc(IPMP_GROUPLIST_SIZE(ngroup)); 581 if (grlistp == NULL) 582 return (NULL); 583 584 grlistp->gl_sig = sig; 585 grlistp->gl_ngroup = ngroup; 586 for (i = 0; i < ngroup; i++) 587 (void) strlcpy(grlistp->gl_groups[i], groups[i], LIFGRNAMSIZ); 588 589 return (grlistp); 590 } 591 592 /* 593 * Clone the group list named by `grlistp'. Returns a pointer to the clone on 594 * success, or NULL on failure. 595 */ 596 ipmp_grouplist_t * 597 ipmp_grouplist_clone(ipmp_grouplist_t *grlistp) 598 { 599 return (ipmp_grouplist_create(grlistp->gl_sig, grlistp->gl_ngroup, 600 grlistp->gl_groups)); 601 } 602 603 /* 604 * Create target information; arguments match ipmp_targinfo_t fields. Returns 605 * a pointer to the new target info on success, or NULL on failure. 606 */ 607 ipmp_targinfo_t * 608 ipmp_targinfo_create(const char *name, struct sockaddr_storage *testaddrp, 609 ipmp_if_targmode_t targmode, uint_t ntarg, struct sockaddr_storage *targs) 610 { 611 ipmp_targinfo_t *targinfop; 612 613 targinfop = malloc(sizeof (ipmp_targinfo_t)); 614 if (targinfop == NULL) 615 return (NULL); 616 617 targinfop->it_testaddr = *testaddrp; 618 targinfop->it_targmode = targmode; 619 targinfop->it_targlistp = ipmp_addrlist_create(ntarg, targs); 620 if (targinfop->it_targlistp == NULL) { 621 ipmp_freetarginfo(targinfop); 622 return (NULL); 623 } 624 (void) strlcpy(targinfop->it_name, name, LIFNAMSIZ); 625 626 return (targinfop); 627 } 628 629 /* 630 * Free the target information pointed to by `targinfop'. 631 */ 632 void 633 ipmp_freetarginfo(ipmp_targinfo_t *targinfop) 634 { 635 free(targinfop->it_targlistp); 636 free(targinfop); 637 } 638 639 /* 640 * Create an interface list; arguments match ipmp_iflist_t fields. Returns a 641 * pointer to the new interface list on success, or NULL on failure. 642 */ 643 static ipmp_iflist_t * 644 ipmp_iflist_create(uint_t nif, char (*ifs)[LIFNAMSIZ]) 645 { 646 unsigned int i; 647 ipmp_iflist_t *iflistp; 648 649 iflistp = malloc(IPMP_IFLIST_SIZE(nif)); 650 if (iflistp == NULL) 651 return (NULL); 652 653 iflistp->il_nif = nif; 654 for (i = 0; i < nif; i++) 655 (void) strlcpy(iflistp->il_ifs[i], ifs[i], LIFNAMSIZ); 656 657 return (iflistp); 658 } 659 660 /* 661 * Free the interface list pointed to by `iflistp'. 662 */ 663 static void 664 ipmp_freeiflist(ipmp_iflist_t *iflistp) 665 { 666 free(iflistp); 667 } 668 669 /* 670 * Create an interface; arguments match ipmp_ifinfo_t fields. Returns a 671 * pointer to the new interface on success, or NULL on failure. 672 */ 673 ipmp_ifinfo_t * 674 ipmp_ifinfo_create(const char *name, const char *group, ipmp_if_state_t state, 675 ipmp_if_type_t type, ipmp_if_linkstate_t linkstate, 676 ipmp_if_probestate_t probestate, ipmp_if_flags_t flags, 677 ipmp_targinfo_t *targinfo4p, ipmp_targinfo_t *targinfo6p) 678 { 679 ipmp_ifinfo_t *ifinfop; 680 681 ifinfop = malloc(sizeof (ipmp_ifinfo_t)); 682 if (ifinfop == NULL) 683 return (NULL); 684 685 (void) strlcpy(ifinfop->if_name, name, LIFNAMSIZ); 686 (void) strlcpy(ifinfop->if_group, group, LIFGRNAMSIZ); 687 688 ifinfop->if_state = state; 689 ifinfop->if_type = type; 690 ifinfop->if_linkstate = linkstate; 691 ifinfop->if_probestate = probestate; 692 ifinfop->if_flags = flags; 693 ifinfop->if_targinfo4 = *targinfo4p; 694 ifinfop->if_targinfo6 = *targinfo6p; 695 696 ifinfop->if_targinfo4.it_targlistp = 697 ipmp_addrlist_clone(targinfo4p->it_targlistp); 698 ifinfop->if_targinfo6.it_targlistp = 699 ipmp_addrlist_clone(targinfo6p->it_targlistp); 700 701 if (ifinfop->if_targinfo4.it_targlistp == NULL || 702 ifinfop->if_targinfo6.it_targlistp == NULL) { 703 ipmp_freeifinfo(ifinfop); 704 return (NULL); 705 } 706 707 return (ifinfop); 708 } 709 710 /* 711 * Clone the interface information named by `ifinfop'. Returns a pointer to 712 * the clone on success, or NULL on failure. 713 */ 714 ipmp_ifinfo_t * 715 ipmp_ifinfo_clone(ipmp_ifinfo_t *ifinfop) 716 { 717 return (ipmp_ifinfo_create(ifinfop->if_name, ifinfop->if_group, 718 ifinfop->if_state, ifinfop->if_type, ifinfop->if_linkstate, 719 ifinfop->if_probestate, ifinfop->if_flags, &ifinfop->if_targinfo4, 720 &ifinfop->if_targinfo6)); 721 } 722 723 /* 724 * Create a group; arguments match ipmp_groupinfo_t fields. Returns a pointer 725 * to the new group on success, or NULL on failure. 726 */ 727 ipmp_groupinfo_t * 728 ipmp_groupinfo_create(const char *name, uint64_t sig, uint_t fdt, 729 ipmp_group_state_t state, uint_t nif, char (*ifs)[LIFNAMSIZ], 730 const char *grifname, const char *m4ifname, const char *m6ifname, 731 const char *bcifname, uint_t naddr, struct sockaddr_storage *addrs) 732 { 733 ipmp_groupinfo_t *grinfop; 734 735 grinfop = malloc(sizeof (ipmp_groupinfo_t)); 736 if (grinfop == NULL) 737 return (NULL); 738 739 grinfop->gr_sig = sig; 740 grinfop->gr_fdt = fdt; 741 grinfop->gr_state = state; 742 grinfop->gr_iflistp = ipmp_iflist_create(nif, ifs); 743 grinfop->gr_adlistp = ipmp_addrlist_create(naddr, addrs); 744 if (grinfop->gr_iflistp == NULL || grinfop->gr_adlistp == NULL) { 745 ipmp_freegroupinfo(grinfop); 746 return (NULL); 747 } 748 (void) strlcpy(grinfop->gr_name, name, LIFGRNAMSIZ); 749 (void) strlcpy(grinfop->gr_ifname, grifname, LIFNAMSIZ); 750 (void) strlcpy(grinfop->gr_m4ifname, m4ifname, LIFNAMSIZ); 751 (void) strlcpy(grinfop->gr_m6ifname, m6ifname, LIFNAMSIZ); 752 (void) strlcpy(grinfop->gr_bcifname, bcifname, LIFNAMSIZ); 753 754 return (grinfop); 755 } 756 757 /* 758 * Clone the group information named by `grinfop'. Returns a pointer to 759 * the clone on success, or NULL on failure. 760 */ 761 ipmp_groupinfo_t * 762 ipmp_groupinfo_clone(ipmp_groupinfo_t *grinfop) 763 { 764 ipmp_addrlist_t *adlistp = grinfop->gr_adlistp; 765 766 return (ipmp_groupinfo_create(grinfop->gr_name, grinfop->gr_sig, 767 grinfop->gr_fdt, grinfop->gr_state, grinfop->gr_iflistp->il_nif, 768 grinfop->gr_iflistp->il_ifs, grinfop->gr_ifname, 769 grinfop->gr_m4ifname, grinfop->gr_m6ifname, grinfop->gr_bcifname, 770 adlistp->al_naddr, adlistp->al_addrs)); 771 } 772 773 /* 774 * Create an address list; arguments match ipmp_addrlist_t fields. Returns 775 * a pointer to the new address list on success, or NULL on failure. 776 */ 777 static ipmp_addrlist_t * 778 ipmp_addrlist_create(uint_t naddr, struct sockaddr_storage *addrs) 779 { 780 unsigned int i; 781 ipmp_addrlist_t *adlistp; 782 783 adlistp = malloc(IPMP_ADDRLIST_SIZE(naddr)); 784 if (adlistp == NULL) 785 return (NULL); 786 787 adlistp->al_naddr = naddr; 788 for (i = 0; i < naddr; i++) 789 adlistp->al_addrs[i] = addrs[i]; 790 791 return (adlistp); 792 } 793 794 /* 795 * Clone the address list named by `adlistp'. Returns a pointer to the clone 796 * on success, or NULL on failure. 797 */ 798 static ipmp_addrlist_t * 799 ipmp_addrlist_clone(ipmp_addrlist_t *adlistp) 800 { 801 return (ipmp_addrlist_create(adlistp->al_naddr, adlistp->al_addrs)); 802 } 803 804 /* 805 * Free the address list pointed to by `adlistp'. 806 */ 807 static void 808 ipmp_freeaddrlist(ipmp_addrlist_t *adlistp) 809 { 810 free(adlistp); 811 } 812 813 /* 814 * Create an address; arguments match ipmp_addrinfo_t fields. Returns a 815 * pointer to the new address on success, or NULL on failure. 816 */ 817 ipmp_addrinfo_t * 818 ipmp_addrinfo_create(struct sockaddr_storage *addrp, ipmp_addr_state_t state, 819 const char *group, const char *binding) 820 { 821 ipmp_addrinfo_t *adinfop; 822 823 adinfop = malloc(sizeof (ipmp_addrinfo_t)); 824 if (adinfop == NULL) 825 return (NULL); 826 827 adinfop->ad_addr = *addrp; 828 adinfop->ad_state = state; 829 (void) strlcpy(adinfop->ad_group, group, LIFGRNAMSIZ); 830 (void) strlcpy(adinfop->ad_binding, binding, LIFNAMSIZ); 831 832 return (adinfop); 833 } 834 835 /* 836 * Clone the address information named by `adinfop'. Returns a pointer to 837 * the clone on success, or NULL on failure. 838 */ 839 ipmp_addrinfo_t * 840 ipmp_addrinfo_clone(ipmp_addrinfo_t *adinfop) 841 { 842 return (ipmp_addrinfo_create(&adinfop->ad_addr, adinfop->ad_state, 843 adinfop->ad_group, adinfop->ad_binding)); 844 } 845 846 /* 847 * Set the query context associated with `handle' to `qcontext', which must be 848 * either IPMP_QCONTEXT_LIVE or IPMP_QCONTEXT_SNAP. Upon success, any 849 * previous snapshot associated with `handle' is discarded. Returns an IPMP 850 * error code. 851 */ 852 int 853 ipmp_setqcontext(ipmp_handle_t handle, ipmp_qcontext_t qcontext) 854 { 855 ipmp_state_t *statep = handle; 856 ipmp_snap_t *snap; 857 int retval; 858 859 switch (qcontext) { 860 case IPMP_QCONTEXT_LIVE: 861 snap = NULL; 862 break; 863 864 case IPMP_QCONTEXT_SNAP: 865 retval = ipmp_snap_take(statep, &snap); 866 if (retval != IPMP_SUCCESS) 867 return (retval); 868 break; 869 870 default: 871 return (IPMP_EINVAL); 872 } 873 874 if (statep->st_snap != NULL) 875 ipmp_snap_free(statep->st_snap); 876 statep->st_snap = snap; 877 878 return (IPMP_SUCCESS); 879 } 880 881 /* 882 * Create an empty snapshot. Returns a pointer to the snapshot on success, 883 * or NULL on failure. 884 */ 885 ipmp_snap_t * 886 ipmp_snap_create(void) 887 { 888 ipmp_snap_t *snap; 889 890 snap = malloc(sizeof (ipmp_snap_t)); 891 if (snap == NULL) 892 return (NULL); 893 894 snap->sn_grlistp = NULL; 895 snap->sn_grinfolistp = NULL; 896 snap->sn_ifinfolistp = NULL; 897 snap->sn_adinfolistp = NULL; 898 snap->sn_ngroup = 0; 899 snap->sn_nif = 0; 900 snap->sn_naddr = 0; 901 902 return (snap); 903 } 904 905 /* 906 * Free all of the resources associated with snapshot `snap'. 907 */ 908 void 909 ipmp_snap_free(ipmp_snap_t *snap) 910 { 911 ipmp_ifinfolist_t *iflp, *ifnext; 912 ipmp_addrinfolist_t *adlp, *adnext; 913 ipmp_groupinfolist_t *grlp, *grnext; 914 915 ipmp_freegrouplist(snap->sn_grlistp); 916 917 for (grlp = snap->sn_grinfolistp; grlp != NULL; grlp = grnext) { 918 grnext = grlp->grl_next; 919 ipmp_freegroupinfo(grlp->grl_grinfop); 920 free(grlp); 921 } 922 923 for (iflp = snap->sn_ifinfolistp; iflp != NULL; iflp = ifnext) { 924 ifnext = iflp->ifl_next; 925 ipmp_freeifinfo(iflp->ifl_ifinfop); 926 free(iflp); 927 } 928 929 for (adlp = snap->sn_adinfolistp; adlp != NULL; adlp = adnext) { 930 adnext = adlp->adl_next; 931 ipmp_freeaddrinfo(adlp->adl_adinfop); 932 free(adlp); 933 } 934 935 free(snap); 936 } 937 938 /* 939 * Add the group information in `grinfop' to the snapshot named by `snap'. 940 * Returns an IPMP error code. 941 */ 942 int 943 ipmp_snap_addgroupinfo(ipmp_snap_t *snap, ipmp_groupinfo_t *grinfop) 944 { 945 ipmp_groupinfolist_t *grlp; 946 947 /* 948 * If the information for this group is already in the snapshot, 949 * in.mpathd is broken. 950 */ 951 if (ipmp_snap_getgroupinfo(snap, grinfop->gr_name) != NULL) 952 return (IPMP_EPROTO); 953 954 grlp = malloc(sizeof (ipmp_groupinfolist_t)); 955 if (grlp == NULL) 956 return (IPMP_ENOMEM); 957 958 grlp->grl_grinfop = grinfop; 959 grlp->grl_next = snap->sn_grinfolistp; 960 snap->sn_grinfolistp = grlp; 961 snap->sn_ngroup++; 962 963 return (IPMP_SUCCESS); 964 } 965 966 /* 967 * Add the interface information in `ifinfop' to the snapshot named by `snap'. 968 * Returns an IPMP error code. 969 */ 970 int 971 ipmp_snap_addifinfo(ipmp_snap_t *snap, ipmp_ifinfo_t *ifinfop) 972 { 973 ipmp_ifinfolist_t *iflp; 974 975 /* 976 * If the information for this interface is already in the snapshot, 977 * in.mpathd is broken. 978 */ 979 if (ipmp_snap_getifinfo(snap, ifinfop->if_name) != NULL) 980 return (IPMP_EPROTO); 981 982 iflp = malloc(sizeof (ipmp_ifinfolist_t)); 983 if (iflp == NULL) 984 return (IPMP_ENOMEM); 985 986 iflp->ifl_ifinfop = ifinfop; 987 iflp->ifl_next = snap->sn_ifinfolistp; 988 snap->sn_ifinfolistp = iflp; 989 snap->sn_nif++; 990 991 return (IPMP_SUCCESS); 992 } 993 994 /* 995 * Add the address information in `adinfop' to the snapshot named by `snap'. 996 * Returns an IPMP error code. 997 */ 998 int 999 ipmp_snap_addaddrinfo(ipmp_snap_t *snap, ipmp_addrinfo_t *adinfop) 1000 { 1001 ipmp_addrinfolist_t *adlp; 1002 1003 /* 1004 * Any duplicate addresses should've already been weeded by in.mpathd. 1005 */ 1006 if (ipmp_snap_getaddrinfo(snap, adinfop->ad_group, 1007 &adinfop->ad_addr) != NULL) 1008 return (IPMP_EPROTO); 1009 1010 adlp = malloc(sizeof (ipmp_addrinfolist_t)); 1011 if (adlp == NULL) 1012 return (IPMP_ENOMEM); 1013 1014 adlp->adl_adinfop = adinfop; 1015 adlp->adl_next = snap->sn_adinfolistp; 1016 snap->sn_adinfolistp = adlp; 1017 snap->sn_naddr++; 1018 1019 return (IPMP_SUCCESS); 1020 } 1021 1022 /* 1023 * Retrieve the information for the group `name' in snapshot `snap'. 1024 * Returns a pointer to the group information on success, or NULL on failure. 1025 */ 1026 static ipmp_groupinfo_t * 1027 ipmp_snap_getgroupinfo(ipmp_snap_t *snap, const char *name) 1028 { 1029 ipmp_groupinfolist_t *grlp; 1030 1031 for (grlp = snap->sn_grinfolistp; grlp != NULL; grlp = grlp->grl_next) { 1032 if (strcmp(grlp->grl_grinfop->gr_name, name) == 0) 1033 break; 1034 } 1035 1036 return (grlp != NULL ? grlp->grl_grinfop : NULL); 1037 } 1038 1039 /* 1040 * Retrieve the information for the interface `name' in snapshot `snap'. 1041 * Returns a pointer to the interface information on success, or NULL on 1042 * failure. 1043 */ 1044 static ipmp_ifinfo_t * 1045 ipmp_snap_getifinfo(ipmp_snap_t *snap, const char *name) 1046 { 1047 ipmp_ifinfolist_t *iflp; 1048 1049 for (iflp = snap->sn_ifinfolistp; iflp != NULL; iflp = iflp->ifl_next) { 1050 if (strcmp(iflp->ifl_ifinfop->if_name, name) == 0) 1051 break; 1052 } 1053 1054 return (iflp != NULL ? iflp->ifl_ifinfop : NULL); 1055 } 1056 1057 /* 1058 * Retrieve the information for the address `addrp' on group `grname' in 1059 * snapshot `snap'. Returns a pointer to the address information on success, 1060 * or NULL on failure. 1061 */ 1062 static ipmp_addrinfo_t * 1063 ipmp_snap_getaddrinfo(ipmp_snap_t *snap, const char *grname, 1064 struct sockaddr_storage *addrp) 1065 { 1066 ipmp_addrinfolist_t *adlp; 1067 1068 for (adlp = snap->sn_adinfolistp; adlp != NULL; adlp = adlp->adl_next) { 1069 if (strcmp(grname, adlp->adl_adinfop->ad_group) == 0 && 1070 sockaddrcmp(addrp, &adlp->adl_adinfop->ad_addr)) 1071 break; 1072 } 1073 1074 return (adlp != NULL ? adlp->adl_adinfop : NULL); 1075 } 1076 1077 /* 1078 * Using `statep', take a snapshot of the IPMP subsystem and if successful 1079 * return it in a dynamically allocated snapshot pointed to by `*snapp'. 1080 * Returns an IPMP error code. 1081 */ 1082 static int 1083 ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp) 1084 { 1085 uint64_t naddr, ngroup, nif; 1086 ipmp_snap_t *snap; 1087 ipmp_infotype_t type; 1088 int retval; 1089 size_t len; 1090 void *infop; 1091 struct timeval end; 1092 1093 naddr = ngroup = nif = UINT64_MAX; 1094 1095 snap = ipmp_snap_create(); 1096 if (snap == NULL) 1097 return (IPMP_ENOMEM); 1098 1099 retval = ipmp_sendquery(statep, IPMP_SNAP, NULL, NULL, &end); 1100 if (retval != IPMP_SUCCESS) { 1101 ipmp_snap_free(snap); 1102 return (retval); 1103 } 1104 1105 /* 1106 * Build up our snapshot. We know there will always be at least four 1107 * TLVs for IPMP_GROUPLIST, IPMP_IFCNT, IPMP_GROUPCNT, and IPMP_ADDRCNT. 1108 * If we receive anything illogical (e.g., more than the expected number 1109 * of interfaces), then bail out. However, to a large extent we have to 1110 * trust the information sent by in.mpathd. 1111 */ 1112 do { 1113 infop = NULL; 1114 retval = ipmp_readtlv(statep->st_fd, &type, &len, &infop, &end); 1115 if (retval != IPMP_SUCCESS) 1116 goto fail; 1117 1118 if (!ipmp_checktlv(type, len, infop)) { 1119 retval = IPMP_EPROTO; 1120 goto fail; 1121 } 1122 1123 switch (type) { 1124 case IPMP_GROUPLIST: 1125 if (snap->sn_grlistp != NULL) { 1126 retval = IPMP_EPROTO; 1127 break; 1128 } 1129 snap->sn_grlistp = infop; 1130 break; 1131 1132 case IPMP_IFINFO: 1133 if (snap->sn_nif == nif) { 1134 retval = IPMP_EPROTO; 1135 break; 1136 } 1137 1138 infop = ipmp_convertifinfo(infop); 1139 if (infop == NULL) { 1140 retval = IPMP_ENOMEM; 1141 break; 1142 } 1143 1144 /* 1145 * Read in V4 and V6 targlist TLVs that follow. 1146 */ 1147 retval = ipmp_readifinfo_lists(statep, infop, &end); 1148 if (retval != IPMP_SUCCESS) 1149 break; 1150 1151 retval = ipmp_snap_addifinfo(snap, infop); 1152 if (retval != IPMP_SUCCESS) { 1153 ipmp_freeifinfo(infop); 1154 infop = NULL; 1155 } 1156 break; 1157 1158 case IPMP_ADDRINFO: 1159 if (snap->sn_naddr == naddr) { 1160 retval = IPMP_EPROTO; 1161 break; 1162 } 1163 1164 retval = ipmp_snap_addaddrinfo(snap, infop); 1165 /* 1166 * NOTE: since we didn't call ipmp_read*info_lists(), 1167 * no need to use ipmp_freeaddrinfo() on failure. 1168 */ 1169 break; 1170 1171 case IPMP_GROUPINFO: 1172 if (snap->sn_ngroup == ngroup) { 1173 retval = IPMP_EPROTO; 1174 break; 1175 } 1176 1177 infop = ipmp_convertgroupinfo(infop); 1178 if (infop == NULL) { 1179 retval = IPMP_ENOMEM; 1180 break; 1181 } 1182 1183 /* 1184 * Read in IPMP groupinfo list TLVs that follow. 1185 */ 1186 retval = ipmp_readgroupinfo_lists(statep, infop, &end); 1187 if (retval != IPMP_SUCCESS) 1188 break; 1189 1190 retval = ipmp_snap_addgroupinfo(snap, infop); 1191 if (retval != IPMP_SUCCESS) { 1192 ipmp_freegroupinfo(infop); 1193 infop = NULL; 1194 } 1195 break; 1196 1197 case IPMP_ADDRCNT: 1198 if (naddr != UINT64_MAX) { 1199 retval = IPMP_EPROTO; 1200 break; 1201 } 1202 1203 naddr = *(uint32_t *)infop; 1204 break; 1205 1206 case IPMP_GROUPCNT: 1207 if (ngroup != UINT64_MAX) { 1208 retval = IPMP_EPROTO; 1209 break; 1210 } 1211 1212 ngroup = *(uint32_t *)infop; 1213 break; 1214 1215 case IPMP_IFCNT: 1216 if (nif != UINT64_MAX) { 1217 retval = IPMP_EPROTO; 1218 break; 1219 } 1220 1221 nif = *(uint32_t *)infop; 1222 break; 1223 1224 default: 1225 retval = IPMP_EPROTO; 1226 break; 1227 } 1228 fail: 1229 if (retval != IPMP_SUCCESS) { 1230 free(infop); 1231 ipmp_snap_free(snap); 1232 return (ipmp_querydone(statep, retval)); 1233 } 1234 } while (snap->sn_grlistp == NULL || snap->sn_nif < nif || 1235 snap->sn_ngroup < ngroup || snap->sn_naddr < naddr); 1236 1237 *snapp = snap; 1238 return (ipmp_querydone(statep, IPMP_SUCCESS)); 1239 } 1240