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