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