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 (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>. 25 * Copyright 2021, Tintri by DDN. All rights reserved. 26 * Copyright 2022, Oxide Computer Company. 27 */ 28 29 /* 30 * Main door handler functions used by ipmgmtd to process the different door 31 * call requests, issued by the library libipadm.so. 32 */ 33 34 #include <alloca.h> 35 #include <pwd.h> 36 #include <auth_attr.h> 37 #include <secdb.h> 38 #include <stdlib.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <errno.h> 43 #include <assert.h> 44 #include <libnvpair.h> 45 #include "ipmgmt_impl.h" 46 47 48 static void ipmgmt_common_handler(char *, char *, db_wfunc_t *); 49 50 /* Handler declaration for each door command */ 51 typedef void ipmgmt_door_handler_t(void *argp); 52 53 static ipmgmt_door_handler_t ipmgmt_getaddr_handler, 54 ipmgmt_getprop_handler, 55 ipmgmt_getif_handler, 56 ipmgmt_initif_handler, 57 ipmgmt_aobjop_handler, 58 ipmgmt_resetaddr_handler, 59 ipmgmt_setif_handler, 60 ipmgmt_resetif_handler, 61 ipmgmt_resetprop_handler, 62 ipmgmt_setaddr_handler, 63 ipmgmt_setprop_handler, 64 ipmgmt_ipmp_update_handler; 65 66 typedef struct ipmgmt_door_info_s { 67 uint_t idi_cmd; 68 boolean_t idi_set; 69 ipmgmt_door_handler_t *idi_handler; 70 } ipmgmt_door_info_t; 71 72 /* maps door commands to door handler functions */ 73 static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = { 74 { IPMGMT_CMD_SETPROP, B_TRUE, ipmgmt_setprop_handler }, 75 { IPMGMT_CMD_SETIF, B_TRUE, ipmgmt_setif_handler }, 76 { IPMGMT_CMD_SETADDR, B_TRUE, ipmgmt_setaddr_handler }, 77 { IPMGMT_CMD_GETPROP, B_FALSE, ipmgmt_getprop_handler }, 78 { IPMGMT_CMD_GETIF, B_FALSE, ipmgmt_getif_handler }, 79 { IPMGMT_CMD_GETADDR, B_FALSE, ipmgmt_getaddr_handler }, 80 { IPMGMT_CMD_RESETIF, B_TRUE, ipmgmt_resetif_handler }, 81 { IPMGMT_CMD_RESETADDR, B_TRUE, ipmgmt_resetaddr_handler }, 82 { IPMGMT_CMD_RESETPROP, B_TRUE, ipmgmt_resetprop_handler }, 83 { IPMGMT_CMD_INITIF, B_TRUE, ipmgmt_initif_handler }, 84 { IPMGMT_CMD_ADDROBJ_LOOKUPADD, B_TRUE, ipmgmt_aobjop_handler }, 85 { IPMGMT_CMD_ADDROBJ_SETLIFNUM, B_TRUE, ipmgmt_aobjop_handler }, 86 { IPMGMT_CMD_ADDROBJ_ADD, B_TRUE, ipmgmt_aobjop_handler }, 87 { IPMGMT_CMD_AOBJNAME2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler }, 88 { IPMGMT_CMD_LIF2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler }, 89 { IPMGMT_CMD_IPMP_UPDATE, B_FALSE, ipmgmt_ipmp_update_handler}, 90 { 0, 0, NULL }, 91 }; 92 93 /* 94 * The main server procedure function that gets invoked for any of the incoming 95 * door commands. Inside this function we identify the incoming command and 96 * invoke the right door handler function. 97 */ 98 /* ARGSUSED */ 99 void 100 ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp, 101 uint_t n_desc) 102 { 103 ipmgmt_door_info_t *infop = NULL; 104 ipmgmt_retval_t retval; 105 int i; 106 uint_t err; 107 ucred_t *cred = NULL; 108 109 for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) { 110 if (i_ipmgmt_door_info_tbl[i].idi_cmd == 111 ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) { 112 infop = &i_ipmgmt_door_info_tbl[i]; 113 break; 114 } 115 } 116 117 if (infop == NULL) { 118 ipmgmt_log(LOG_ERR, "Invalid door command specified"); 119 err = EINVAL; 120 goto fail; 121 } 122 123 /* check for solaris.network.interface.config authorization */ 124 if (infop->idi_set) { 125 uid_t uid; 126 struct passwd pwd; 127 char buf[1024]; 128 129 if (door_ucred(&cred) != 0) { 130 err = errno; 131 ipmgmt_log(LOG_ERR, "Could not get user credentials."); 132 goto fail; 133 } 134 uid = ucred_getruid(cred); 135 if ((int)uid < 0) { 136 err = errno; 137 ipmgmt_log(LOG_ERR, "Could not get user id."); 138 goto fail; 139 } 140 if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == 141 NULL) { 142 err = errno; 143 ipmgmt_log(LOG_ERR, "Could not get password entry."); 144 goto fail; 145 } 146 if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, 147 pwd.pw_name) != 1) { 148 err = EPERM; 149 ipmgmt_log(LOG_ERR, "Not authorized for operation."); 150 goto fail; 151 } 152 ucred_free(cred); 153 } 154 155 /* individual handlers take care of calling door_return */ 156 infop->idi_handler((void *)argp); 157 return; 158 fail: 159 ucred_free(cred); 160 retval.ir_err = err; 161 (void) door_return((char *)&retval, sizeof (retval), NULL, 0); 162 } 163 164 /* 165 * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted 166 * property value for the given property. 167 */ 168 static void 169 ipmgmt_getprop_handler(void *argp) 170 { 171 ipmgmt_prop_arg_t *pargp = argp; 172 ipmgmt_getprop_rval_t rval, *rvalp = &rval; 173 174 assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP); 175 176 rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ); 177 if (rvalp->ir_err == 0) 178 (void) strlcpy(rvalp->ir_pval, pargp->ia_pval, 179 sizeof (rvalp->ir_pval)); 180 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0); 181 } 182 183 /* 184 * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value 185 * for the given property in the DB. 186 */ 187 static void 188 ipmgmt_setprop_handler(void *argp) 189 { 190 ipmgmt_prop_arg_t *pargp = argp; 191 ipmgmt_retval_t rval; 192 ipadm_dbwrite_cbarg_t cb; 193 nvlist_t *nvl = NULL; 194 int err; 195 196 assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP); 197 198 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) 199 goto fail; 200 if (pargp->ia_module[0] != '\0' && 201 (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME, 202 pargp->ia_module)) != 0) { 203 goto fail; 204 } 205 if (pargp->ia_ifname[0] != '\0' && 206 (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME, 207 pargp->ia_ifname)) != 0) 208 goto fail; 209 if (pargp->ia_aobjname[0] != '\0' && 210 (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, 211 pargp->ia_aobjname)) != 0) 212 goto fail; 213 if ((err = nvlist_add_string(nvl, pargp->ia_pname, 214 pargp->ia_pval)) != 0) 215 goto fail; 216 217 cb.dbw_nvl = nvl; 218 cb.dbw_flags = pargp->ia_flags; 219 err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE); 220 fail: 221 nvlist_free(nvl); 222 rval.ir_err = err; 223 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 224 } 225 226 /* 227 * Helper function for ipmgmt_setaddr_handler(). 228 * It converts the nvlist_t, `nvl', to aobjmap node `nodep'. 229 */ 230 static int 231 i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep) 232 { 233 char *aobjname = NULL, *ifname = NULL; 234 int32_t lnum; 235 nvlist_t *nvladdr; 236 sa_family_t af = AF_UNSPEC; 237 ipadm_addr_type_t addrtype = IPADM_ADDR_NONE; 238 int err = 0; 239 240 /* 241 * Retrieve all the information needed to build '*nodep' from 242 * nvlist_t nvl. 243 */ 244 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME, 245 &aobjname)) != 0 || 246 (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 || 247 (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) { 248 return (err); 249 } 250 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) { 251 af = AF_INET; 252 addrtype = IPADM_ADDR_STATIC; 253 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvladdr) == 0) { 254 char *reqhost; 255 256 af = AF_INET; 257 addrtype = IPADM_ADDR_DHCP; 258 259 /* 260 * ipmgmt_am_reqhost comes through in `nvl' for purposes of 261 * updating the cached representation, but it is persisted as 262 * a stand-alone DB line; so remove it after copying it. 263 */ 264 if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) { 265 *nodep->ipmgmt_am_reqhost = '\0'; 266 } else { 267 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST, 268 &reqhost)) != 0) 269 return (err); 270 271 (void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost, 272 sizeof (nodep->ipmgmt_am_reqhost)); 273 (void) nvlist_remove(nvl, IPADM_NVP_REQHOST, 274 DATA_TYPE_STRING); 275 } 276 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) { 277 af = AF_INET6; 278 addrtype = IPADM_ADDR_STATIC; 279 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) { 280 struct sockaddr_in6 sin6 = {0}; 281 uint8_t *addr6; 282 uint32_t plen; 283 uint_t n; 284 285 af = AF_INET6; 286 addrtype = IPADM_ADDR_IPV6_ADDRCONF; 287 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN, 288 &plen) != 0) 289 return (EINVAL); 290 if (plen != 0) { 291 if (nvlist_lookup_uint8_array(nvladdr, 292 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0) 293 return (EINVAL); 294 bcopy(addr6, &sin6.sin6_addr, n); 295 } 296 297 nodep->ipmgmt_am_linklocal = B_TRUE; 298 nodep->ipmgmt_am_ifid = sin6; 299 } 300 301 /* 302 * populate the non-addrtype-specific `*nodep' with retrieved values. 303 */ 304 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname)); 305 (void) strlcpy(nodep->am_aobjname, aobjname, 306 sizeof (nodep->am_aobjname)); 307 nodep->am_lnum = lnum; 308 nodep->am_family = af; 309 nodep->am_atype = addrtype; 310 nodep->am_next = NULL; 311 312 /* 313 * Do not store logical interface number in persistent store as it 314 * takes different value on reboot. So remove it from `nvl'. 315 */ 316 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM)) 317 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32); 318 319 return (0); 320 } 321 322 /* 323 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object 324 * node to the list `aobjmap' and optionally persists the address 325 * information in the DB. 326 */ 327 static void 328 ipmgmt_setaddr_handler(void *argp) 329 { 330 ipmgmt_setaddr_arg_t *sargp = argp; 331 ipmgmt_retval_t rval; 332 ipmgmt_aobjmap_t node = {0}; 333 nvlist_t *nvl = NULL; 334 char *nvlbuf; 335 size_t nvlsize = sargp->ia_nvlsize; 336 uint32_t flags = sargp->ia_flags; 337 int err = 0; 338 339 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t); 340 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, 0)) != 0) 341 goto ret; 342 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) { 343 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0) 344 goto ret; 345 if (flags & IPMGMT_INIT) 346 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST); 347 else 348 node.am_flags = flags & ~IPMGMT_PROPS_ONLY; 349 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0) 350 goto ret; 351 } 352 if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) { 353 ipadm_dbwrite_cbarg_t cb; 354 355 cb.dbw_nvl = nvl; 356 cb.dbw_flags = 0; 357 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE); 358 } 359 ret: 360 nvlist_free(nvl); 361 rval.ir_err = err; 362 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 363 } 364 365 /* 366 * Handles the door commands that read or modify the `aobjmap' structure. 367 * 368 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap' 369 * after ensuring that the namespace is not taken. If required, also 370 * generates an `aobjname' for address object for the library to use. 371 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap' 372 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object 373 * associated with that logical interface. 374 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical 375 * interface associated with that address object. 376 */ 377 static void 378 ipmgmt_aobjop_handler(void *argp) 379 { 380 ipmgmt_aobjop_arg_t *largp = argp; 381 ipmgmt_retval_t rval; 382 ipmgmt_aobjop_rval_t aobjrval; 383 void *rvalp; 384 size_t rsize; 385 ipmgmt_aobjmap_t node; 386 int err = 0; 387 char *ifname = largp->ia_ifname; 388 char *aobjname = largp->ia_aobjname; 389 int32_t lnum = largp->ia_lnum; 390 sa_family_t af = largp->ia_family; 391 ipadm_addr_type_t atype = largp->ia_atype; 392 ipmgmt_aobjmap_t *head; 393 394 switch (largp->ia_cmd) { 395 case IPMGMT_CMD_ADDROBJ_LOOKUPADD: 396 rsize = sizeof (ipmgmt_aobjop_rval_t); 397 rvalp = &aobjrval; 398 bzero(&node, sizeof (node)); 399 (void) strlcpy(node.am_aobjname, aobjname, 400 sizeof (node.am_aobjname)); 401 (void) strlcpy(node.am_ifname, ifname, 402 sizeof (node.am_ifname)); 403 node.am_family = af; 404 node.am_atype = atype; 405 if (atype == IPADM_ADDR_IPV6_ADDRCONF) { 406 node.ipmgmt_am_linklocal = B_TRUE; 407 } 408 /* no logical number is associated with this addrobj yet */ 409 node.am_lnum = -1; 410 /* The address object is not persisted yet. */ 411 node.am_flags = IPMGMT_ACTIVE; 412 err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD); 413 if (err == 0) { 414 (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname, 415 sizeof (aobjrval.ir_aobjname)); 416 } 417 break; 418 case IPMGMT_CMD_ADDROBJ_SETLIFNUM: 419 rsize = sizeof (ipmgmt_retval_t); 420 rvalp = &rval; 421 bzero(&node, sizeof (node)); 422 (void) strlcpy(node.am_aobjname, aobjname, 423 sizeof (node.am_aobjname)); 424 (void) strlcpy(node.am_ifname, ifname, 425 sizeof (node.am_ifname)); 426 node.am_family = af; 427 node.am_lnum = lnum; 428 err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM); 429 break; 430 case IPMGMT_CMD_ADDROBJ_ADD: 431 rsize = sizeof (ipmgmt_retval_t); 432 rvalp = &rval; 433 if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 || 434 af == AF_UNSPEC) { 435 err = EINVAL; 436 break; 437 } 438 bzero(&node, sizeof (node)); 439 (void) strlcpy(node.am_aobjname, aobjname, 440 sizeof (node.am_aobjname)); 441 (void) strlcpy(node.am_ifname, ifname, 442 sizeof (node.am_ifname)); 443 node.am_atype = atype; 444 node.am_lnum = lnum; 445 node.am_family = af; 446 /* The address object is not persisted. */ 447 node.am_flags = IPMGMT_ACTIVE; 448 err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD); 449 break; 450 case IPMGMT_CMD_AOBJNAME2ADDROBJ: 451 rsize = sizeof (ipmgmt_aobjop_rval_t); 452 rvalp = &aobjrval; 453 bzero(&aobjrval, sizeof (aobjrval)); 454 if (aobjname[0] == '\0') { 455 err = EINVAL; 456 break; 457 } 458 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock); 459 head = aobjmap.aobjmap_head; 460 for (; head; head = head->am_next) { 461 if (strcmp(head->am_aobjname, aobjname) != 0) 462 continue; 463 /* 464 * For an auto-configured interface, return 465 * the lifnum that has the link-local on it. 466 * Other logical interfaces were created for 467 * prefixes and dhcpv6 addresses and do not 468 * have am_ifid set. 469 */ 470 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF || 471 head->ipmgmt_am_linklocal) { 472 break; 473 } 474 } 475 if (head == NULL) { 476 err = ENOENT; 477 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 478 break; 479 } 480 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname, 481 sizeof (aobjrval.ir_ifname)); 482 aobjrval.ir_lnum = head->am_lnum; 483 aobjrval.ir_family = head->am_family; 484 aobjrval.ir_flags = head->am_flags; 485 aobjrval.ir_atype = head->am_atype; 486 aobjrval.ir_atype_cache = head->am_atype_cache; 487 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 488 break; 489 case IPMGMT_CMD_LIF2ADDROBJ: 490 rsize = sizeof (ipmgmt_aobjop_rval_t); 491 rvalp = &aobjrval; 492 bzero(&aobjrval, sizeof (aobjrval)); 493 if (ifname[0] == '\0') { 494 err = EINVAL; 495 break; 496 } 497 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock); 498 head = aobjmap.aobjmap_head; 499 for (; head; head = head->am_next) { 500 if (strcmp(head->am_ifname, ifname) == 0 && 501 head->am_lnum == lnum && 502 head->am_family == af) { 503 break; 504 } 505 } 506 if (head == NULL) { 507 err = ENOENT; 508 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 509 break; 510 } 511 (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname, 512 sizeof (aobjrval.ir_aobjname)); 513 aobjrval.ir_atype = head->am_atype; 514 aobjrval.ir_flags = head->am_flags; 515 aobjrval.ir_atype_cache = head->am_atype_cache; 516 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 517 break; 518 default: 519 rsize = sizeof (ipmgmt_retval_t); 520 rvalp = &rval; 521 err = EINVAL; 522 } 523 ((ipmgmt_retval_t *)rvalp)->ir_err = err; 524 (void) door_return((char *)rvalp, rsize, NULL, 0); 525 } 526 527 /* 528 * Given an interface name and family, deletes all the address objects 529 * associated with it. 530 */ 531 void 532 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags) 533 { 534 ipmgmt_aobjmap_t *head, *next, *prev; 535 ipadm_db_op_t db_op; 536 537 prev = NULL; 538 539 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock); 540 head = aobjmap.aobjmap_head; 541 for (; head; head = next) { 542 next = head->am_next; 543 if (strcmp(head->am_ifname, ifname) != 0 || 544 head->am_family != af) { 545 prev = head; 546 continue; 547 } 548 549 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) && 550 flags == IPMGMT_ACTIVE) { 551 /* 552 * If the addres is present in both active and 553 * persistent store, and if we are performing 554 * a temporary delete, we update the node to 555 * indicate that the address is only present in 556 * persistent store and we proceed. Otherwise 557 * we always delete the node from aobjmap. 558 */ 559 head->am_flags &= ~IPMGMT_ACTIVE; 560 head->am_lnum = -1; 561 db_op = IPADM_DB_WRITE; 562 } else { 563 db_op = IPADM_DB_DELETE; 564 if (prev == NULL) 565 aobjmap.aobjmap_head = next; 566 else 567 prev->am_next = next; 568 } 569 (void) ipmgmt_persist_aobjmap(head, db_op); 570 if (db_op == IPADM_DB_DELETE) 571 free(head); 572 } 573 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 574 } 575 576 /* 577 * Handles the door command IPMGMT_CMD_SETIF. It persists the interface 578 * information in the DB. 579 */ 580 static void 581 ipmgmt_setif_handler(void *argp) 582 { 583 ipmgmt_retval_t rval; 584 585 rval.ir_err = ipmgmt_persist_if(argp); 586 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 587 } 588 589 /* 590 * Handles the door command IPMGMT_CMD_RESETIF. For the given interface, 591 * deletes all the persisted interface configuration. It also deletes, from 592 * `aobjmap', all the address objects configured on the given interface. 593 */ 594 static void 595 ipmgmt_resetif_handler(void *argp) 596 { 597 ipmgmt_if_arg_t *rargp = argp; 598 ipmgmt_retval_t rval; 599 ipmgmt_if_cbarg_t cbarg; 600 uint32_t flags = rargp->ia_flags; 601 int err = 0; 602 603 cbarg.cb_family = rargp->ia_family; 604 cbarg.cb_ifname = rargp->ia_ifname; 605 606 cbarg.cb_ipv4exists = B_TRUE; 607 cbarg.cb_ipv6exists = B_TRUE; 608 609 if (flags & IPMGMT_PERSIST) 610 err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg, 611 IPADM_DB_DELETE); 612 613 if (flags & IPMGMT_ACTIVE) 614 i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family, 615 flags); 616 617 rval.ir_err = err; 618 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 619 } 620 621 /* 622 * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj 623 * deletes all the persisted addrobj configuration. It also deletes the 624 * corresponding node, from `aobjmap'. 625 */ 626 static void 627 ipmgmt_resetaddr_handler(void *argp) 628 { 629 ipmgmt_addr_arg_t *rargp = argp; 630 ipmgmt_retval_t rval; 631 ipmgmt_aobjmap_t node; 632 uint32_t flags = rargp->ia_flags; 633 int err = 0; 634 ipmgmt_resetaddr_cbarg_t cbarg; 635 636 cbarg.cb_aobjname = rargp->ia_aobjname; 637 638 if (flags & IPMGMT_PERSIST) 639 err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg, 640 IPADM_DB_DELETE); 641 642 if (flags & IPMGMT_ACTIVE) { 643 bzero(&node, sizeof (node)); 644 (void) strlcpy(node.am_aobjname, rargp->ia_aobjname, 645 sizeof (node.am_aobjname)); 646 647 /* 648 * am_lnum is used only for IPv6 autoconf case, since there 649 * can be multiple nodes with the same aobjname. 650 */ 651 node.am_lnum = rargp->ia_lnum; 652 node.am_flags = flags; 653 (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE); 654 } 655 656 rval.ir_err = err; 657 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 658 } 659 660 /* 661 * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted 662 * address for a given `gargp->ia_aobjname'. If it is not defined then it 663 * retrieves all the addresses configured on `gargp->ia_ifname'. The 664 * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this 665 * handler through library. 666 */ 667 static void 668 ipmgmt_getaddr_handler(void *argp) 669 { 670 ipmgmt_getaddr_arg_t *gargp = argp; 671 672 ipmgmt_common_handler(gargp->ia_ifname, gargp->ia_aobjname, 673 ipmgmt_db_getaddr); 674 } 675 676 /* 677 * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line 678 * from the DB. 679 */ 680 static void 681 ipmgmt_resetprop_handler(void *argp) 682 { 683 ipmgmt_prop_arg_t *pargp = argp; 684 ipmgmt_retval_t rval; 685 686 assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP); 687 688 rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp, 689 IPADM_DB_DELETE); 690 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 691 } 692 693 /* 694 * Handles the door command IPMGMT_CMD_GETIF. It retrieves the names of all 695 * persisted interfaces and the IP protocol families (IPv4 or IPv6) they 696 * support. Returns the info as a nvlist using door_return() from 697 * ipmgmt_common_handler(). 698 */ 699 static void 700 ipmgmt_getif_handler(void *argp) 701 { 702 ipmgmt_getif_arg_t *getif = argp; 703 704 assert(getif->ia_cmd == IPMGMT_CMD_GETIF); 705 706 ipmgmt_common_handler(getif->ia_ifname, NULL, 707 ipmgmt_db_getif); 708 } 709 710 /* 711 * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted 712 * interface configuration (interface properties and addresses), for all those 713 * interfaces that need to be initialized. 714 */ 715 static void 716 ipmgmt_initif_handler(void *argp) 717 { 718 ipmgmt_initif_arg_t *initif = argp; 719 size_t buflen, nvlsize; 720 char *buf = NULL, *onvlbuf, *invlbuf; 721 ipmgmt_get_rval_t rval, *rvalp = &rval; 722 ipmgmt_initif_cbarg_t cbarg; 723 int err; 724 725 assert(initif->ia_cmd == IPMGMT_CMD_INITIF); 726 727 bzero(&cbarg, sizeof (cbarg)); 728 invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t); 729 nvlsize = initif->ia_nvlsize; 730 err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, 0); 731 if (err != 0) 732 goto fail; 733 734 cbarg.cb_family = initif->ia_family; 735 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0) 736 goto fail; 737 738 err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ); 739 if (err == ENOENT && cbarg.cb_ocnt > 0) { 740 /* 741 * If there is at least one entry in the nvlist, 742 * do not return error. 743 */ 744 err = 0; 745 } 746 if (err != 0) 747 goto fail; 748 749 if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0) 750 goto fail; 751 752 if (nvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t))) 753 goto fail; 754 755 buflen = nvlsize + sizeof (ipmgmt_get_rval_t); 756 /* 757 * We cannot use malloc() here because door_return never returns, and 758 * memory allocated by malloc() would get leaked. Use alloca() instead. 759 */ 760 buf = alloca(buflen); 761 onvlbuf = buf + sizeof (ipmgmt_get_rval_t); 762 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize, 763 NV_ENCODE_NATIVE, 0)) != 0) { 764 goto fail; 765 } 766 nvlist_free(cbarg.cb_invl); 767 nvlist_free(cbarg.cb_onvl); 768 rvalp = (ipmgmt_get_rval_t *)(void *)buf; 769 rvalp->ir_err = 0; 770 rvalp->ir_nvlsize = nvlsize; 771 772 (void) door_return(buf, buflen, NULL, 0); 773 return; 774 fail: 775 nvlist_free(cbarg.cb_invl); 776 nvlist_free(cbarg.cb_onvl); 777 rvalp->ir_err = err; 778 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0); 779 } 780 781 int 782 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp) 783 { 784 ipadm_dbwrite_cbarg_t cb; 785 uint32_t flags = sargp->ia_flags; 786 nvlist_t *nvl = NULL; 787 char strval[IPMGMT_STRSIZE]; 788 int err = 0; 789 790 if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC || 791 sargp->ia_ifname[0] == '\0') { 792 err = EINVAL; 793 goto ret; 794 } 795 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) 796 goto ret; 797 798 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME, 799 sargp->ia_ifname)) != 0) 800 goto ret; 801 802 if ((err = ipmgmt_update_family_nvp(nvl, sargp->ia_family, 803 IPMGMT_APPEND)) != 0) 804 goto ret; 805 806 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_ifclass); 807 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFCLASS, strval)) != 0) 808 goto ret; 809 810 cb.dbw_nvl = nvl; 811 cb.dbw_flags = IPMGMT_APPEND | IPMGMT_UPDATE_IF; 812 err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE); 813 ret: 814 nvlist_free(nvl); 815 return (err); 816 } 817 818 /* 819 * The helper for ipmgmt_getif_handler and ipmgmt_getaddr_handler 820 */ 821 static void 822 ipmgmt_common_handler(char *if_name, char *aobj_name, db_wfunc_t worker) 823 { 824 size_t buflen, onvlsize; 825 char *buf, *onvlbuf; 826 ipmgmt_get_cbarg_t cbarg; 827 ipmgmt_get_rval_t rval, *rvalp = &rval; 828 int err = 0; 829 830 cbarg.cb_ifname = if_name; 831 cbarg.cb_aobjname = aobj_name; 832 cbarg.cb_ocnt = 0; 833 834 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0) 835 goto fail; 836 837 err = ipmgmt_db_walk(worker, &cbarg, IPADM_DB_READ); 838 if (err == ENOENT && cbarg.cb_ocnt > 0) { 839 /* 840 * If there is at least one entry in the nvlist, 841 * do not return error. 842 */ 843 err = 0; 844 } 845 if (err != 0) 846 goto fail; 847 848 if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize, 849 NV_ENCODE_NATIVE)) != 0) 850 goto fail; 851 852 if (onvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t))) 853 goto fail; 854 855 buflen = onvlsize + sizeof (ipmgmt_get_rval_t); 856 /* 857 * We cannot use malloc() here because door_return never returns, and 858 * memory allocated by malloc() would get leaked. Use alloca() instead. 859 */ 860 buf = alloca(buflen); 861 onvlbuf = buf + sizeof (ipmgmt_get_rval_t); 862 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, 863 &onvlsize, NV_ENCODE_NATIVE, 0)) != 0) 864 goto fail; 865 866 nvlist_free(cbarg.cb_onvl); 867 rvalp = (ipmgmt_get_rval_t *)(void *)buf; 868 rvalp->ir_err = 0; 869 rvalp->ir_nvlsize = onvlsize; 870 871 (void) door_return(buf, buflen, NULL, 0); 872 873 fail: 874 nvlist_free(cbarg.cb_onvl); 875 rvalp->ir_err = err; 876 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0); 877 } 878 879 /* 880 * Handles the door command IPMGMT_CMD_IPMP_UPDATE 881 */ 882 static void 883 ipmgmt_ipmp_update_handler(void *argp) 884 { 885 ipmgmt_ipmp_update_arg_t *uargp = argp; 886 ipmgmt_retval_t rval; 887 ipadm_dbwrite_cbarg_t cb; 888 889 boolean_t gif_exists; 890 char gifname[LIFNAMSIZ]; 891 nvlist_t *nvl = NULL; 892 uint32_t flags = uargp->ia_flags; 893 int err = 0; 894 895 assert(uargp->ia_cmd == IPMGMT_CMD_IPMP_UPDATE); 896 897 gif_exists = ipmgmt_persist_if_exists(uargp->ia_gifname, 898 AF_UNSPEC); 899 900 if (!ipmgmt_persist_if_exists(uargp->ia_mifname, AF_UNSPEC)) { 901 err = EINVAL; 902 goto ret; 903 } 904 905 ipmgmt_get_group_interface(uargp->ia_mifname, gifname, LIFNAMSIZ); 906 907 if (flags & IPMGMT_APPEND) { 908 /* Group interface should be available in the DB */ 909 if (!gif_exists) { 910 err = ENOENT; 911 goto ret; 912 } 913 914 if (gifname[0] != '\0') { 915 err = EEXIST; 916 goto ret; 917 } 918 } 919 920 if (flags & IPMGMT_REMOVE) { 921 /* We cannot remove something that does not exist */ 922 if (!gif_exists || gifname[0] == '\0') { 923 err = ENOENT; 924 goto ret; 925 } 926 if (strcmp(uargp->ia_gifname, gifname) != 0) { 927 err = EINVAL; 928 goto ret; 929 } 930 } 931 932 if (flags & IPMGMT_PERSIST) { 933 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) 934 goto ret; 935 936 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME, 937 uargp->ia_gifname)) != 0) 938 goto ret; 939 940 if ((err = nvlist_add_string(nvl, IPADM_NVP_MIFNAMES, 941 uargp->ia_mifname)) != 0) 942 goto ret; 943 944 if ((err = nvlist_add_string(nvl, IPADM_NVP_GIFNAME, 945 uargp->ia_gifname)) != 0) 946 goto ret; 947 948 cb.dbw_nvl = nvl; 949 cb.dbw_flags = flags | IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP; 950 err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE); 951 } 952 ret: 953 nvlist_free(nvl); 954 rval.ir_err = err; 955 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 956 } 957