8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / lib / ipmgmtd / ipmgmt_door.c
blob8e9e153b21f6b5e342d5097702c377e2920d5df1
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];
121 if (door_ucred(&cred) != 0) {
122 err = errno;
123 ipmgmt_log(LOG_ERR, "Could not get user credentials.");
124 goto fail;
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;
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;
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;
144 ucred_free(cred);
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);
157 * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
158 * property value for the given property.
160 static void
161 ipmgmt_getprop_handler(void *argp)
163 ipmgmt_prop_arg_t *pargp = argp;
164 ipmgmt_getprop_rval_t rval, *rvalp = &rval;
166 assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
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);
176 * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
177 * for the given property in the DB.
179 static void
180 ipmgmt_setprop_handler(void *argp)
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;
188 assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
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;
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;
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);
219 * Helper function for ipmgmt_setaddr_handler().
220 * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
222 static int
223 i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
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;
235 * Retrieve all the information needed to build '*nodep' from
236 * nvlist_t nvl.
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);
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;
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));
274 * populate the `*nodep' with retrieved values.
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;
286 nodep->am_next = NULL;
289 * Do not store logical interface number in persistent store as it
290 * takes different value on reboot. So remove it from `nvl'.
292 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
293 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
295 return (0);
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.
303 static void
304 ipmgmt_setaddr_handler(void *argp)
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;
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;
328 if (flags & IPMGMT_PERSIST) {
329 ipadm_dbwrite_cbarg_t cb;
331 cb.dbw_nvl = nvl;
332 cb.dbw_flags = 0;
333 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
335 ret:
336 nvlist_free(nvl);
337 rval.ir_err = err;
338 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
342 * Handles the door commands that modify the `aobjmap' structure.
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.
353 static void
354 ipmgmt_aobjop_handler(void *argp)
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;
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));
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;
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;
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;
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.
443 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
444 head->am_linklocal) {
445 break;
448 if (head == NULL) {
449 err = ENOENT;
450 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
451 break;
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;
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;
481 if (head == NULL) {
482 err = ENOENT;
483 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
484 break;
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;
497 ((ipmgmt_retval_t *)rvalp)->ir_err = err;
498 (void) door_return((char *)rvalp, rsize, NULL, 0);
502 * Given an interface name and family, deletes all the address objects
503 * associated with it.
505 void
506 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
508 ipmgmt_aobjmap_t *head, *next, *prev;
509 ipadm_db_op_t db_op;
511 prev = NULL;
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;
523 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
524 flags == IPMGMT_ACTIVE) {
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.
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;
543 (void) ipmgmt_persist_aobjmap(head, db_op);
544 if (db_op == IPADM_DB_DELETE)
545 free(head);
547 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
551 * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
552 * information in the DB.
554 static void
555 ipmgmt_setif_handler(void *argp)
557 ipmgmt_retval_t rval;
559 rval.ir_err = ipmgmt_persist_if(argp);
560 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
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.
568 static void
569 ipmgmt_resetif_handler(void *argp)
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;
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);
583 if (flags & IPMGMT_ACTIVE)
584 i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
585 flags);
587 rval.ir_err = err;
588 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
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'.
596 static void
597 ipmgmt_resetaddr_handler(void *argp)
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;
606 cbarg.cb_aobjname = rargp->ia_aobjname;
608 if (flags & IPMGMT_PERSIST)
609 err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
610 IPADM_DB_DELETE);
612 if (flags & IPMGMT_ACTIVE) {
613 bzero(&node, sizeof (node));
614 (void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
615 sizeof (node.am_aobjname));
618 * am_lnum is used only for IPv6 autoconf case, since there
619 * can be multiple nodes with the same aobjname.
621 node.am_lnum = rargp->ia_lnum;
622 node.am_flags = flags;
623 (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
626 rval.ir_err = err;
627 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
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.
637 static void
638 ipmgmt_getaddr_handler(void *argp)
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;
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) {
655 * If there is atleast one entry in the nvlist,
656 * do not return error.
658 err = 0;
660 if (err != 0)
661 goto fail;
663 if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
664 NV_ENCODE_NATIVE)) != 0) {
665 goto fail;
667 buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
669 * We cannot use malloc() here because door_return never returns, and
670 * memory allocated by malloc() would get leaked. Use alloca() instead.
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;
678 nvlist_free(cbarg.cb_onvl);
679 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
680 rvalp->ir_err = 0;
681 rvalp->ir_nvlsize = onvlsize;
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);
692 * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
693 * from the DB.
695 static void
696 ipmgmt_resetprop_handler(void *argp)
698 ipmgmt_prop_arg_t *pargp = argp;
699 ipmgmt_retval_t rval;
701 assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
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);
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.
712 static void
713 ipmgmt_getif_handler(void *argp)
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;
723 assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
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) {
730 * If there is atleast one entry in the nvlist,
731 * do not return error.
733 err = 0;
735 if (err != 0) {
736 rval.ir_err = err;
737 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
738 return;
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);
748 rvalp->ir_ifcnt = count;
749 rifp = rvalp->ir_ifinfo;
750 ifp = cbarg.cb_ifinfo;
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
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;
765 rvalp->ir_err = err;
766 (void) door_return((char *)rvalp, rbufsize, NULL, 0);
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.
774 static void
775 ipmgmt_initif_handler(void *argp)
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;
784 assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
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;
793 cbarg.cb_family = initif->ia_family;
794 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
795 goto fail;
797 err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
798 if (err == ENOENT && cbarg.cb_ocnt > 0) {
800 * If there is atleast one entry in the nvlist,
801 * do not return error.
803 err = 0;
805 if (err != 0)
806 goto fail;
808 if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
809 goto fail;
810 buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
812 * We cannot use malloc() here because door_return never returns, and
813 * memory allocated by malloc() would get leaked. Use alloca() instead.
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;
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;
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);
837 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
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];
845 if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
846 sargp->ia_ifname[0] == '\0') {
847 err = EINVAL;
848 goto ret;
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);