dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / lib / ipmgmtd / ipmgmt_door.c
blobc990c4b0d525417c629e21bb7ac9311fe0444e5f
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
27 * Main door handler functions used by ipmgmtd to process the different door
28 * call requests, issued by the library libipadm.so.
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"
44 /* Handler declaration for each door command */
45 typedef void ipmgmt_door_handler_t(void *argp);
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;
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;
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 },
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.
90 /* ARGSUSED */
91 void
92 ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
93 uint_t n_desc)
95 ipmgmt_door_info_t *infop = NULL;
96 ipmgmt_retval_t retval;
97 int i;
98 uint_t err;
99 ucred_t *cred = NULL;
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;
109 if (infop == NULL) {
110 ipmgmt_log(LOG_ERR, "Invalid door command specified");
111 err = EINVAL;
112 goto fail;
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 struct passwd *result;
122 if (door_ucred(&cred) != 0) {
123 err = errno;
124 ipmgmt_log(LOG_ERR, "Could not get user credentials.");
125 goto fail;
127 uid = ucred_getruid(cred);
128 if ((int)uid < 0) {
129 err = errno;
130 ipmgmt_log(LOG_ERR, "Could not get user id.");
131 goto fail;
133 getpwuid_r(uid, &pwd, buf, sizeof (buf), &result);
134 if (!result) {
135 err = errno;
136 ipmgmt_log(LOG_ERR, "Could not get password entry.");
137 goto fail;
139 if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
140 pwd.pw_name) != 1) {
141 err = EPERM;
142 ipmgmt_log(LOG_ERR, "Not authorized for operation.");
143 goto fail;
145 ucred_free(cred);
148 /* individual handlers take care of calling door_return */
149 infop->idi_handler((void *)argp);
150 return;
151 fail:
152 ucred_free(cred);
153 retval.ir_err = err;
154 (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
158 * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
159 * property value for the given property.
161 static void
162 ipmgmt_getprop_handler(void *argp)
164 ipmgmt_prop_arg_t *pargp = argp;
165 ipmgmt_getprop_rval_t rval, *rvalp = &rval;
167 assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
169 rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ);
170 if (rvalp->ir_err == 0)
171 (void) strlcpy(rvalp->ir_pval, pargp->ia_pval,
172 sizeof (rvalp->ir_pval));
173 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
177 * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
178 * for the given property in the DB.
180 static void
181 ipmgmt_setprop_handler(void *argp)
183 ipmgmt_prop_arg_t *pargp = argp;
184 ipmgmt_retval_t rval;
185 ipadm_dbwrite_cbarg_t cb;
186 nvlist_t *nvl = NULL;
187 int err;
189 assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
191 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
192 goto fail;
193 if (pargp->ia_module[0] != '\0' &&
194 (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME,
195 pargp->ia_module)) != 0) {
196 goto fail;
198 if (pargp->ia_ifname[0] != '\0' &&
199 (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
200 pargp->ia_ifname)) != 0)
201 goto fail;
202 if (pargp->ia_aobjname[0] != '\0' &&
203 (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME,
204 pargp->ia_aobjname)) != 0)
205 goto fail;
206 if ((err = nvlist_add_string(nvl, pargp->ia_pname,
207 pargp->ia_pval)) != 0)
208 goto fail;
210 cb.dbw_nvl = nvl;
211 cb.dbw_flags = pargp->ia_flags;
212 err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
213 fail:
214 nvlist_free(nvl);
215 rval.ir_err = err;
216 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
220 * Helper function for ipmgmt_setaddr_handler().
221 * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
223 static int
224 i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
226 char *aobjname = NULL, *ifname = NULL;
227 int32_t lnum;
228 nvlist_t *nvladdr;
229 struct sockaddr_storage addr;
230 uint_t n;
231 sa_family_t af = AF_UNSPEC;
232 ipadm_addr_type_t addrtype = IPADM_ADDR_NONE;
233 int err = 0;
236 * Retrieve all the information needed to build '*nodep' from
237 * nvlist_t nvl.
239 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
240 &aobjname)) != 0 ||
241 (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 ||
242 (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) {
243 return (err);
245 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
246 af = AF_INET;
247 addrtype = IPADM_ADDR_STATIC;
248 } else if (nvlist_exists(nvl, IPADM_NVP_DHCP)) {
249 af = AF_INET;
250 addrtype = IPADM_ADDR_DHCP;
251 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
252 af = AF_INET6;
253 addrtype = IPADM_ADDR_STATIC;
254 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
255 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
256 uint8_t *addr6;
257 uint32_t plen;
259 af = AF_INET6;
260 addrtype = IPADM_ADDR_IPV6_ADDRCONF;
261 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
262 &plen) != 0)
263 return (EINVAL);
264 if (plen != 0) {
265 if (nvlist_lookup_uint8_array(nvladdr,
266 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
267 return (EINVAL);
268 bcopy(addr6, &sin6->sin6_addr, n);
269 } else {
270 bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
275 * populate the `*nodep' with retrieved values.
277 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
278 (void) strlcpy(nodep->am_aobjname, aobjname,
279 sizeof (nodep->am_aobjname));
280 nodep->am_lnum = lnum;
281 nodep->am_family = af;
282 nodep->am_atype = addrtype;
283 if (addrtype == IPADM_ADDR_IPV6_ADDRCONF) {
284 nodep->am_linklocal = B_TRUE;
285 nodep->am_ifid = addr;
287 nodep->am_next = NULL;
290 * Do not store logical interface number in persistent store as it
291 * takes different value on reboot. So remove it from `nvl'.
293 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
294 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
296 return (0);
300 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
301 * node to the list `aobjmap' and then persists the address information in the
302 * DB.
304 static void
305 ipmgmt_setaddr_handler(void *argp)
307 ipmgmt_setaddr_arg_t *sargp = argp;
308 ipmgmt_retval_t rval;
309 ipmgmt_aobjmap_t node;
310 nvlist_t *nvl = NULL;
311 char *nvlbuf;
312 size_t nvlsize = sargp->ia_nvlsize;
313 uint32_t flags = sargp->ia_flags;
314 int err = 0;
316 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
317 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
318 goto ret;
319 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
320 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
321 goto ret;
322 if (flags & IPMGMT_INIT)
323 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
324 else
325 node.am_flags = flags;
326 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
327 goto ret;
329 if (flags & IPMGMT_PERSIST) {
330 ipadm_dbwrite_cbarg_t cb;
332 cb.dbw_nvl = nvl;
333 cb.dbw_flags = 0;
334 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
336 ret:
337 nvlist_free(nvl);
338 rval.ir_err = err;
339 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
343 * Handles the door commands that modify the `aobjmap' structure.
345 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
346 * after ensuring that the namespace is not taken. If required, also
347 * generates an `aobjname' for address object for the library to use.
348 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
349 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
350 * associated with that logical interface.
351 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
352 * interface associated with that address object.
354 static void
355 ipmgmt_aobjop_handler(void *argp)
357 ipmgmt_aobjop_arg_t *largp = argp;
358 ipmgmt_retval_t rval;
359 ipmgmt_aobjop_rval_t aobjrval;
360 void *rvalp;
361 size_t rsize;
362 ipmgmt_aobjmap_t node;
363 int err = 0;
364 char *ifname = largp->ia_ifname;
365 char *aobjname = largp->ia_aobjname;
366 int32_t lnum = largp->ia_lnum;
367 sa_family_t af = largp->ia_family;
368 ipadm_addr_type_t atype = largp->ia_atype;
369 ipmgmt_aobjmap_t *head;
371 switch (largp->ia_cmd) {
372 case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
373 rsize = sizeof (ipmgmt_aobjop_rval_t);
374 rvalp = &aobjrval;
375 bzero(&node, sizeof (node));
376 (void) strlcpy(node.am_aobjname, aobjname,
377 sizeof (node.am_aobjname));
378 (void) strlcpy(node.am_ifname, ifname,
379 sizeof (node.am_ifname));
380 node.am_family = af;
381 node.am_atype = atype;
382 /* no logical number is associated with this addrobj yet */
383 node.am_lnum = -1;
384 /* The address object is not persisted yet. */
385 node.am_flags = IPMGMT_ACTIVE;
386 err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
387 if (err == 0) {
388 (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
389 sizeof (aobjrval.ir_aobjname));
391 break;
392 case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
393 rsize = sizeof (ipmgmt_retval_t);
394 rvalp = &rval;
395 bzero(&node, sizeof (node));
396 (void) strlcpy(node.am_aobjname, aobjname,
397 sizeof (node.am_aobjname));
398 (void) strlcpy(node.am_ifname, ifname,
399 sizeof (node.am_ifname));
400 node.am_family = af;
401 node.am_lnum = lnum;
402 err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
403 break;
404 case IPMGMT_CMD_ADDROBJ_ADD:
405 rsize = sizeof (ipmgmt_retval_t);
406 rvalp = &rval;
407 if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
408 af == AF_UNSPEC) {
409 err = EINVAL;
410 break;
412 bzero(&node, sizeof (node));
413 (void) strlcpy(node.am_aobjname, aobjname,
414 sizeof (node.am_aobjname));
415 (void) strlcpy(node.am_ifname, ifname,
416 sizeof (node.am_ifname));
417 node.am_atype = atype;
418 node.am_lnum = lnum;
419 node.am_family = af;
420 /* The address object is not persisted. */
421 node.am_flags = IPMGMT_ACTIVE;
422 err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
423 break;
424 case IPMGMT_CMD_AOBJNAME2ADDROBJ:
425 rsize = sizeof (ipmgmt_aobjop_rval_t);
426 rvalp = &aobjrval;
427 bzero(&aobjrval, sizeof (aobjrval));
428 if (aobjname[0] == '\0') {
429 err = EINVAL;
430 break;
432 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
433 head = aobjmap.aobjmap_head;
434 for (; head; head = head->am_next) {
435 if (strcmp(head->am_aobjname, aobjname) != 0)
436 continue;
438 * For an auto-configured interface, return
439 * the lifnum that has the link-local on it.
440 * Other logical interfaces were created for
441 * prefixes and dhcpv6 addresses and do not
442 * have am_ifid set.
444 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
445 head->am_linklocal) {
446 break;
449 if (head == NULL) {
450 err = ENOENT;
451 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
452 break;
454 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
455 sizeof (aobjrval.ir_ifname));
456 aobjrval.ir_lnum = head->am_lnum;
457 aobjrval.ir_family = head->am_family;
458 aobjrval.ir_flags = head->am_flags;
459 aobjrval.ir_atype = head->am_atype;
460 if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF &&
461 head->am_linklocal)
462 aobjrval.ir_ifid = head->am_ifid;
463 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
464 break;
465 case IPMGMT_CMD_LIF2ADDROBJ:
466 rsize = sizeof (ipmgmt_aobjop_rval_t);
467 rvalp = &aobjrval;
468 bzero(&aobjrval, sizeof (aobjrval));
469 if (ifname[0] == '\0') {
470 err = EINVAL;
471 break;
473 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
474 head = aobjmap.aobjmap_head;
475 for (; head; head = head->am_next) {
476 if (strcmp(head->am_ifname, ifname) == 0 &&
477 head->am_lnum == lnum &&
478 head->am_family == af) {
479 break;
482 if (head == NULL) {
483 err = ENOENT;
484 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
485 break;
487 (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
488 sizeof (aobjrval.ir_aobjname));
489 aobjrval.ir_atype = head->am_atype;
490 aobjrval.ir_flags = head->am_flags;
491 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
492 break;
493 default:
494 rsize = sizeof (ipmgmt_retval_t);
495 rvalp = &rval;
496 err = EINVAL;
498 ((ipmgmt_retval_t *)rvalp)->ir_err = err;
499 (void) door_return((char *)rvalp, rsize, NULL, 0);
503 * Given an interface name and family, deletes all the address objects
504 * associated with it.
506 void
507 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
509 ipmgmt_aobjmap_t *head, *next, *prev;
510 ipadm_db_op_t db_op;
512 prev = NULL;
514 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
515 head = aobjmap.aobjmap_head;
516 for (; head; head = next) {
517 next = head->am_next;
518 if (strcmp(head->am_ifname, ifname) != 0 ||
519 head->am_family != af) {
520 prev = head;
521 continue;
524 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
525 flags == IPMGMT_ACTIVE) {
527 * If the addres is present in both active and
528 * persistent store, and if we are performing
529 * a temporary delete, we update the node to
530 * indicate that the address is only present in
531 * persistent store and we proceed. Otherwise
532 * we always delete the node from aobjmap.
534 head->am_flags &= ~IPMGMT_ACTIVE;
535 head->am_lnum = -1;
536 db_op = IPADM_DB_WRITE;
537 } else {
538 db_op = IPADM_DB_DELETE;
539 if (prev == NULL)
540 aobjmap.aobjmap_head = next;
541 else
542 prev->am_next = next;
544 (void) ipmgmt_persist_aobjmap(head, db_op);
545 if (db_op == IPADM_DB_DELETE)
546 free(head);
548 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
552 * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
553 * information in the DB.
555 static void
556 ipmgmt_setif_handler(void *argp)
558 ipmgmt_retval_t rval;
560 rval.ir_err = ipmgmt_persist_if(argp);
561 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
565 * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
566 * deletes all the persisted interface configuration. It also deletes, from
567 * `aobjmap', all the address objects configured on the given interface.
569 static void
570 ipmgmt_resetif_handler(void *argp)
572 ipmgmt_if_arg_t *rargp = argp;
573 ipmgmt_retval_t rval;
574 ipmgmt_if_cbarg_t cbarg;
575 uint32_t flags = rargp->ia_flags;
576 int err = 0;
578 cbarg.cb_family = rargp->ia_family;
579 cbarg.cb_ifname = rargp->ia_ifname;
580 if (flags & IPMGMT_PERSIST)
581 err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
582 IPADM_DB_DELETE);
584 if (flags & IPMGMT_ACTIVE)
585 i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
586 flags);
588 rval.ir_err = err;
589 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
593 * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
594 * deletes all the persisted addrobj configuration. It also deletes the
595 * corresponding node, from `aobjmap'.
597 static void
598 ipmgmt_resetaddr_handler(void *argp)
600 ipmgmt_addr_arg_t *rargp = argp;
601 ipmgmt_retval_t rval;
602 ipmgmt_aobjmap_t node;
603 uint32_t flags = rargp->ia_flags;
604 int err = 0;
605 ipmgmt_resetaddr_cbarg_t cbarg;
607 cbarg.cb_aobjname = rargp->ia_aobjname;
609 if (flags & IPMGMT_PERSIST)
610 err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
611 IPADM_DB_DELETE);
613 if (flags & IPMGMT_ACTIVE) {
614 bzero(&node, sizeof (node));
615 (void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
616 sizeof (node.am_aobjname));
619 * am_lnum is used only for IPv6 autoconf case, since there
620 * can be multiple nodes with the same aobjname.
622 node.am_lnum = rargp->ia_lnum;
623 node.am_flags = flags;
624 (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
627 rval.ir_err = err;
628 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
632 * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
633 * address for a given `gargp->ia_aobjname'. If it is not defined then it
634 * retrieves all the addresses configured on `gargp->ia_ifname'. The
635 * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
636 * handler through library.
638 static void
639 ipmgmt_getaddr_handler(void *argp)
641 size_t buflen, onvlsize;
642 char *buf, *onvlbuf;
643 ipmgmt_getaddr_arg_t *gargp = argp;
644 ipmgmt_getaddr_cbarg_t cbarg;
645 ipmgmt_get_rval_t rval, *rvalp = &rval;
646 int err = 0;
648 cbarg.cb_ifname = gargp->ia_ifname;
649 cbarg.cb_aobjname = gargp->ia_aobjname;
650 cbarg.cb_ocnt = 0;
651 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
652 goto fail;
653 err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
654 if (err == ENOENT && cbarg.cb_ocnt > 0) {
656 * If there is atleast one entry in the nvlist,
657 * do not return error.
659 err = 0;
661 if (err != 0)
662 goto fail;
664 if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
665 NV_ENCODE_NATIVE)) != 0) {
666 goto fail;
668 buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
670 * We cannot use malloc() here because door_return never returns, and
671 * memory allocated by malloc() would get leaked. Use alloca() instead.
673 buf = alloca(buflen);
674 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
675 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
676 NV_ENCODE_NATIVE, 0)) != 0) {
677 goto fail;
679 nvlist_free(cbarg.cb_onvl);
680 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
681 rvalp->ir_err = 0;
682 rvalp->ir_nvlsize = onvlsize;
684 (void) door_return(buf, buflen, NULL, 0);
685 return;
686 fail:
687 nvlist_free(cbarg.cb_onvl);
688 rvalp->ir_err = err;
689 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
693 * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
694 * from the DB.
696 static void
697 ipmgmt_resetprop_handler(void *argp)
699 ipmgmt_prop_arg_t *pargp = argp;
700 ipmgmt_retval_t rval;
702 assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
704 rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
705 IPADM_DB_DELETE);
706 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
710 * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
711 * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
713 static void
714 ipmgmt_getif_handler(void *argp)
716 ipmgmt_getif_arg_t *getif = argp;
717 ipmgmt_getif_rval_t *rvalp;
718 ipmgmt_retval_t rval;
719 ipmgmt_getif_cbarg_t cbarg;
720 ipadm_if_info_t *ifp, *rifp, *curifp;
721 int i, err = 0, count = 0;
722 size_t rbufsize;
724 assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
726 bzero(&cbarg, sizeof (cbarg));
727 cbarg.cb_ifname = getif->ia_ifname;
728 err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
729 if (err == ENOENT && cbarg.cb_ifinfo) {
731 * If there is atleast one entry in the nvlist,
732 * do not return error.
734 err = 0;
736 if (err != 0) {
737 rval.ir_err = err;
738 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
739 return;
742 /* allocate sufficient buffer to return the interface info */
743 for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
744 ++count;
745 rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
746 rvalp = alloca(rbufsize);
747 bzero(rvalp, rbufsize);
749 rvalp->ir_ifcnt = count;
750 rifp = rvalp->ir_ifinfo;
751 ifp = cbarg.cb_ifinfo;
754 * copy the interface info to buffer allocated on stack. The reason
755 * we do this is to avoid memory leak, as door_return() would never
756 * return
758 for (i = 0; i < count; i++) {
759 rifp = rvalp->ir_ifinfo + i;
760 (void) bcopy(ifp, rifp, sizeof (*rifp));
761 rifp->ifi_next = NULL;
762 curifp = ifp->ifi_next;
763 free(ifp);
764 ifp = curifp;
766 rvalp->ir_err = err;
767 (void) door_return((char *)rvalp, rbufsize, NULL, 0);
771 * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
772 * interface configuration (interface properties and addresses), for all those
773 * interfaces that need to be initialized.
775 static void
776 ipmgmt_initif_handler(void *argp)
778 ipmgmt_initif_arg_t *initif = argp;
779 size_t buflen, nvlsize;
780 char *buf = NULL, *onvlbuf, *invlbuf;
781 ipmgmt_get_rval_t rval, *rvalp = &rval;
782 ipmgmt_initif_cbarg_t cbarg;
783 int err;
785 assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
787 bzero(&cbarg, sizeof (cbarg));
788 invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
789 nvlsize = initif->ia_nvlsize;
790 err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
791 if (err != 0)
792 goto fail;
794 cbarg.cb_family = initif->ia_family;
795 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
796 goto fail;
798 err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
799 if (err == ENOENT && cbarg.cb_ocnt > 0) {
801 * If there is atleast one entry in the nvlist,
802 * do not return error.
804 err = 0;
806 if (err != 0)
807 goto fail;
809 if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
810 goto fail;
811 buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
813 * We cannot use malloc() here because door_return never returns, and
814 * memory allocated by malloc() would get leaked. Use alloca() instead.
816 buf = alloca(buflen);
817 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
818 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
819 NV_ENCODE_NATIVE, 0)) != 0) {
820 goto fail;
822 nvlist_free(cbarg.cb_invl);
823 nvlist_free(cbarg.cb_onvl);
824 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
825 rvalp->ir_err = 0;
826 rvalp->ir_nvlsize = nvlsize;
828 (void) door_return(buf, buflen, NULL, 0);
829 return;
830 fail:
831 nvlist_free(cbarg.cb_invl);
832 nvlist_free(cbarg.cb_onvl);
833 rvalp->ir_err = err;
834 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
838 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
840 ipadm_dbwrite_cbarg_t cb;
841 uint32_t flags = sargp->ia_flags;
842 nvlist_t *nvl = NULL;
843 int err = 0;
844 char strval[IPMGMT_STRSIZE];
846 if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
847 sargp->ia_ifname[0] == '\0') {
848 err = EINVAL;
849 goto ret;
851 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
852 goto ret;
853 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
854 sargp->ia_ifname)) != 0)
855 goto ret;
856 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
857 if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
858 goto ret;
859 cb.dbw_nvl = nvl;
860 cb.dbw_flags = 0;
861 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
862 ret:
863 nvlist_free(nvl);
864 return (err);