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