7388 Support -h <hostname> for ipadm DHCP
[unleashed.git] / usr / src / cmd / cmd-inet / lib / ipmgmtd / ipmgmt_door.c
blobc83c7627adf9dc537664ede274279421a39e0f3c
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.
24 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
28 * Main door handler functions used by ipmgmtd to process the different door
29 * call requests, issued by the library libipadm.so.
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"
45 /* Handler declaration for each door command */
46 typedef void ipmgmt_door_handler_t(void *argp);
48 static ipmgmt_door_handler_t ipmgmt_getaddr_handler,
49 ipmgmt_getprop_handler,
50 ipmgmt_getif_handler,
51 ipmgmt_initif_handler,
52 ipmgmt_aobjop_handler,
53 ipmgmt_resetaddr_handler,
54 ipmgmt_setif_handler,
55 ipmgmt_resetif_handler,
56 ipmgmt_resetprop_handler,
57 ipmgmt_setaddr_handler,
58 ipmgmt_setprop_handler;
60 typedef struct ipmgmt_door_info_s {
61 uint_t idi_cmd;
62 boolean_t idi_set;
63 ipmgmt_door_handler_t *idi_handler;
64 } ipmgmt_door_info_t;
66 /* maps door commands to door handler functions */
67 static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = {
68 { IPMGMT_CMD_SETPROP, B_TRUE, ipmgmt_setprop_handler },
69 { IPMGMT_CMD_SETIF, B_TRUE, ipmgmt_setif_handler },
70 { IPMGMT_CMD_SETADDR, B_TRUE, ipmgmt_setaddr_handler },
71 { IPMGMT_CMD_GETPROP, B_FALSE, ipmgmt_getprop_handler },
72 { IPMGMT_CMD_GETIF, B_FALSE, ipmgmt_getif_handler },
73 { IPMGMT_CMD_GETADDR, B_FALSE, ipmgmt_getaddr_handler },
74 { IPMGMT_CMD_RESETIF, B_TRUE, ipmgmt_resetif_handler },
75 { IPMGMT_CMD_RESETADDR, B_TRUE, ipmgmt_resetaddr_handler },
76 { IPMGMT_CMD_RESETPROP, B_TRUE, ipmgmt_resetprop_handler },
77 { IPMGMT_CMD_INITIF, B_TRUE, ipmgmt_initif_handler },
78 { IPMGMT_CMD_ADDROBJ_LOOKUPADD, B_TRUE, ipmgmt_aobjop_handler },
79 { IPMGMT_CMD_ADDROBJ_SETLIFNUM, B_TRUE, ipmgmt_aobjop_handler },
80 { IPMGMT_CMD_ADDROBJ_ADD, B_TRUE, ipmgmt_aobjop_handler },
81 { IPMGMT_CMD_AOBJNAME2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler },
82 { IPMGMT_CMD_LIF2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler },
83 { 0, 0, NULL },
87 * The main server procedure function that gets invoked for any of the incoming
88 * door commands. Inside this function we identify the incoming command and
89 * invoke the right door handler function.
91 /* ARGSUSED */
92 void
93 ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
94 uint_t n_desc)
96 ipmgmt_door_info_t *infop = NULL;
97 ipmgmt_retval_t retval;
98 int i;
99 uint_t err;
100 ucred_t *cred = NULL;
102 for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) {
103 if (i_ipmgmt_door_info_tbl[i].idi_cmd ==
104 ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) {
105 infop = &i_ipmgmt_door_info_tbl[i];
106 break;
110 if (infop == NULL) {
111 ipmgmt_log(LOG_ERR, "Invalid door command specified");
112 err = EINVAL;
113 goto fail;
116 /* check for solaris.network.interface.config authorization */
117 if (infop->idi_set) {
118 uid_t uid;
119 struct passwd pwd;
120 char buf[1024];
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 if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) ==
134 NULL) {
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 sa_family_t af = AF_UNSPEC;
230 ipadm_addr_type_t addrtype = IPADM_ADDR_NONE;
231 int err = 0;
234 * Retrieve all the information needed to build '*nodep' from
235 * nvlist_t nvl.
237 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
238 &aobjname)) != 0 ||
239 (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 ||
240 (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) {
241 return (err);
243 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
244 af = AF_INET;
245 addrtype = IPADM_ADDR_STATIC;
246 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvladdr) == 0) {
247 char *reqhost;
249 af = AF_INET;
250 addrtype = IPADM_ADDR_DHCP;
253 * ipmgmt_am_reqhost comes through in `nvl' for purposes of
254 * updating the cached representation, but it is persisted as
255 * a stand-alone DB line; so remove it after copying it.
257 if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) {
258 *nodep->ipmgmt_am_reqhost = '\0';
259 } else {
260 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST,
261 &reqhost)) != 0)
262 return (err);
264 (void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost,
265 sizeof (nodep->ipmgmt_am_reqhost));
266 (void) nvlist_remove(nvl, IPADM_NVP_REQHOST,
267 DATA_TYPE_STRING);
269 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
270 af = AF_INET6;
271 addrtype = IPADM_ADDR_STATIC;
272 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
273 struct sockaddr_in6 sin6 = {0};
274 uint8_t *addr6;
275 uint32_t plen;
276 uint_t n;
278 af = AF_INET6;
279 addrtype = IPADM_ADDR_IPV6_ADDRCONF;
280 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
281 &plen) != 0)
282 return (EINVAL);
283 if (plen != 0) {
284 if (nvlist_lookup_uint8_array(nvladdr,
285 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
286 return (EINVAL);
287 bcopy(addr6, &sin6.sin6_addr, n);
290 nodep->ipmgmt_am_linklocal = B_TRUE;
291 nodep->ipmgmt_am_ifid = sin6;
295 * populate the non-addrtype-specific `*nodep' with retrieved values.
297 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
298 (void) strlcpy(nodep->am_aobjname, aobjname,
299 sizeof (nodep->am_aobjname));
300 nodep->am_lnum = lnum;
301 nodep->am_family = af;
302 nodep->am_atype = addrtype;
303 nodep->am_next = NULL;
306 * Do not store logical interface number in persistent store as it
307 * takes different value on reboot. So remove it from `nvl'.
309 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
310 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
312 return (0);
316 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
317 * node to the list `aobjmap' and optionally persists the address
318 * information in the DB.
320 static void
321 ipmgmt_setaddr_handler(void *argp)
323 ipmgmt_setaddr_arg_t *sargp = argp;
324 ipmgmt_retval_t rval;
325 ipmgmt_aobjmap_t node = {0};
326 nvlist_t *nvl = NULL;
327 char *nvlbuf;
328 size_t nvlsize = sargp->ia_nvlsize;
329 uint32_t flags = sargp->ia_flags;
330 int err = 0;
332 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
333 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
334 goto ret;
335 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
336 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
337 goto ret;
338 if (flags & IPMGMT_INIT)
339 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
340 else
341 node.am_flags = flags & ~IPMGMT_PROPS_ONLY;
342 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
343 goto ret;
345 if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) {
346 ipadm_dbwrite_cbarg_t cb;
348 cb.dbw_nvl = nvl;
349 cb.dbw_flags = 0;
350 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
352 ret:
353 nvlist_free(nvl);
354 rval.ir_err = err;
355 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
359 * Handles the door commands that read or modify the `aobjmap' structure.
361 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
362 * after ensuring that the namespace is not taken. If required, also
363 * generates an `aobjname' for address object for the library to use.
364 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
365 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
366 * associated with that logical interface.
367 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
368 * interface associated with that address object.
370 static void
371 ipmgmt_aobjop_handler(void *argp)
373 ipmgmt_aobjop_arg_t *largp = argp;
374 ipmgmt_retval_t rval;
375 ipmgmt_aobjop_rval_t aobjrval;
376 void *rvalp;
377 size_t rsize;
378 ipmgmt_aobjmap_t node;
379 int err = 0;
380 char *ifname = largp->ia_ifname;
381 char *aobjname = largp->ia_aobjname;
382 int32_t lnum = largp->ia_lnum;
383 sa_family_t af = largp->ia_family;
384 ipadm_addr_type_t atype = largp->ia_atype;
385 ipmgmt_aobjmap_t *head;
387 switch (largp->ia_cmd) {
388 case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
389 rsize = sizeof (ipmgmt_aobjop_rval_t);
390 rvalp = &aobjrval;
391 bzero(&node, sizeof (node));
392 (void) strlcpy(node.am_aobjname, aobjname,
393 sizeof (node.am_aobjname));
394 (void) strlcpy(node.am_ifname, ifname,
395 sizeof (node.am_ifname));
396 node.am_family = af;
397 node.am_atype = atype;
398 /* no logical number is associated with this addrobj yet */
399 node.am_lnum = -1;
400 /* The address object is not persisted yet. */
401 node.am_flags = IPMGMT_ACTIVE;
402 err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
403 if (err == 0) {
404 (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
405 sizeof (aobjrval.ir_aobjname));
407 break;
408 case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
409 rsize = sizeof (ipmgmt_retval_t);
410 rvalp = &rval;
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_family = af;
417 node.am_lnum = lnum;
418 err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
419 break;
420 case IPMGMT_CMD_ADDROBJ_ADD:
421 rsize = sizeof (ipmgmt_retval_t);
422 rvalp = &rval;
423 if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
424 af == AF_UNSPEC) {
425 err = EINVAL;
426 break;
428 bzero(&node, sizeof (node));
429 (void) strlcpy(node.am_aobjname, aobjname,
430 sizeof (node.am_aobjname));
431 (void) strlcpy(node.am_ifname, ifname,
432 sizeof (node.am_ifname));
433 node.am_atype = atype;
434 node.am_lnum = lnum;
435 node.am_family = af;
436 /* The address object is not persisted. */
437 node.am_flags = IPMGMT_ACTIVE;
438 err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
439 break;
440 case IPMGMT_CMD_AOBJNAME2ADDROBJ:
441 rsize = sizeof (ipmgmt_aobjop_rval_t);
442 rvalp = &aobjrval;
443 bzero(&aobjrval, sizeof (aobjrval));
444 if (aobjname[0] == '\0') {
445 err = EINVAL;
446 break;
448 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
449 head = aobjmap.aobjmap_head;
450 for (; head; head = head->am_next) {
451 if (strcmp(head->am_aobjname, aobjname) != 0)
452 continue;
454 * For an auto-configured interface, return
455 * the lifnum that has the link-local on it.
456 * Other logical interfaces were created for
457 * prefixes and dhcpv6 addresses and do not
458 * have am_ifid set.
460 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
461 head->ipmgmt_am_linklocal) {
462 break;
465 if (head == NULL) {
466 err = ENOENT;
467 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
468 break;
470 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
471 sizeof (aobjrval.ir_ifname));
472 aobjrval.ir_lnum = head->am_lnum;
473 aobjrval.ir_family = head->am_family;
474 aobjrval.ir_flags = head->am_flags;
475 aobjrval.ir_atype = head->am_atype;
476 aobjrval.ir_atype_cache = head->am_atype_cache;
477 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
478 break;
479 case IPMGMT_CMD_LIF2ADDROBJ:
480 rsize = sizeof (ipmgmt_aobjop_rval_t);
481 rvalp = &aobjrval;
482 bzero(&aobjrval, sizeof (aobjrval));
483 if (ifname[0] == '\0') {
484 err = EINVAL;
485 break;
487 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
488 head = aobjmap.aobjmap_head;
489 for (; head; head = head->am_next) {
490 if (strcmp(head->am_ifname, ifname) == 0 &&
491 head->am_lnum == lnum &&
492 head->am_family == af) {
493 break;
496 if (head == NULL) {
497 err = ENOENT;
498 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
499 break;
501 (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
502 sizeof (aobjrval.ir_aobjname));
503 aobjrval.ir_atype = head->am_atype;
504 aobjrval.ir_flags = head->am_flags;
505 aobjrval.ir_atype_cache = head->am_atype_cache;
506 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
507 break;
508 default:
509 rsize = sizeof (ipmgmt_retval_t);
510 rvalp = &rval;
511 err = EINVAL;
513 ((ipmgmt_retval_t *)rvalp)->ir_err = err;
514 (void) door_return((char *)rvalp, rsize, NULL, 0);
518 * Given an interface name and family, deletes all the address objects
519 * associated with it.
521 void
522 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
524 ipmgmt_aobjmap_t *head, *next, *prev;
525 ipadm_db_op_t db_op;
527 prev = NULL;
529 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
530 head = aobjmap.aobjmap_head;
531 for (; head; head = next) {
532 next = head->am_next;
533 if (strcmp(head->am_ifname, ifname) != 0 ||
534 head->am_family != af) {
535 prev = head;
536 continue;
539 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
540 flags == IPMGMT_ACTIVE) {
542 * If the addres is present in both active and
543 * persistent store, and if we are performing
544 * a temporary delete, we update the node to
545 * indicate that the address is only present in
546 * persistent store and we proceed. Otherwise
547 * we always delete the node from aobjmap.
549 head->am_flags &= ~IPMGMT_ACTIVE;
550 head->am_lnum = -1;
551 db_op = IPADM_DB_WRITE;
552 } else {
553 db_op = IPADM_DB_DELETE;
554 if (prev == NULL)
555 aobjmap.aobjmap_head = next;
556 else
557 prev->am_next = next;
559 (void) ipmgmt_persist_aobjmap(head, db_op);
560 if (db_op == IPADM_DB_DELETE)
561 free(head);
563 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
567 * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
568 * information in the DB.
570 static void
571 ipmgmt_setif_handler(void *argp)
573 ipmgmt_retval_t rval;
575 rval.ir_err = ipmgmt_persist_if(argp);
576 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
580 * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
581 * deletes all the persisted interface configuration. It also deletes, from
582 * `aobjmap', all the address objects configured on the given interface.
584 static void
585 ipmgmt_resetif_handler(void *argp)
587 ipmgmt_if_arg_t *rargp = argp;
588 ipmgmt_retval_t rval;
589 ipmgmt_if_cbarg_t cbarg;
590 uint32_t flags = rargp->ia_flags;
591 int err = 0;
593 cbarg.cb_family = rargp->ia_family;
594 cbarg.cb_ifname = rargp->ia_ifname;
595 if (flags & IPMGMT_PERSIST)
596 err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
597 IPADM_DB_DELETE);
599 if (flags & IPMGMT_ACTIVE)
600 i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
601 flags);
603 rval.ir_err = err;
604 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
608 * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
609 * deletes all the persisted addrobj configuration. It also deletes the
610 * corresponding node, from `aobjmap'.
612 static void
613 ipmgmt_resetaddr_handler(void *argp)
615 ipmgmt_addr_arg_t *rargp = argp;
616 ipmgmt_retval_t rval;
617 ipmgmt_aobjmap_t node;
618 uint32_t flags = rargp->ia_flags;
619 int err = 0;
620 ipmgmt_resetaddr_cbarg_t cbarg;
622 cbarg.cb_aobjname = rargp->ia_aobjname;
624 if (flags & IPMGMT_PERSIST)
625 err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
626 IPADM_DB_DELETE);
628 if (flags & IPMGMT_ACTIVE) {
629 bzero(&node, sizeof (node));
630 (void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
631 sizeof (node.am_aobjname));
634 * am_lnum is used only for IPv6 autoconf case, since there
635 * can be multiple nodes with the same aobjname.
637 node.am_lnum = rargp->ia_lnum;
638 node.am_flags = flags;
639 (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
642 rval.ir_err = err;
643 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
647 * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
648 * address for a given `gargp->ia_aobjname'. If it is not defined then it
649 * retrieves all the addresses configured on `gargp->ia_ifname'. The
650 * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
651 * handler through library.
653 static void
654 ipmgmt_getaddr_handler(void *argp)
656 size_t buflen, onvlsize;
657 char *buf, *onvlbuf;
658 ipmgmt_getaddr_arg_t *gargp = argp;
659 ipmgmt_getaddr_cbarg_t cbarg;
660 ipmgmt_get_rval_t rval, *rvalp = &rval;
661 int err = 0;
663 cbarg.cb_ifname = gargp->ia_ifname;
664 cbarg.cb_aobjname = gargp->ia_aobjname;
665 cbarg.cb_ocnt = 0;
666 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
667 goto fail;
668 err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
669 if (err == ENOENT && cbarg.cb_ocnt > 0) {
671 * If there is atleast one entry in the nvlist,
672 * do not return error.
674 err = 0;
676 if (err != 0)
677 goto fail;
679 if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
680 NV_ENCODE_NATIVE)) != 0) {
681 goto fail;
683 buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
685 * We cannot use malloc() here because door_return never returns, and
686 * memory allocated by malloc() would get leaked. Use alloca() instead.
688 buf = alloca(buflen);
689 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
690 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
691 NV_ENCODE_NATIVE, 0)) != 0) {
692 goto fail;
694 nvlist_free(cbarg.cb_onvl);
695 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
696 rvalp->ir_err = 0;
697 rvalp->ir_nvlsize = onvlsize;
699 (void) door_return(buf, buflen, NULL, 0);
700 return;
701 fail:
702 nvlist_free(cbarg.cb_onvl);
703 rvalp->ir_err = err;
704 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
708 * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
709 * from the DB.
711 static void
712 ipmgmt_resetprop_handler(void *argp)
714 ipmgmt_prop_arg_t *pargp = argp;
715 ipmgmt_retval_t rval;
717 assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
719 rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
720 IPADM_DB_DELETE);
721 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
725 * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
726 * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
728 static void
729 ipmgmt_getif_handler(void *argp)
731 ipmgmt_getif_arg_t *getif = argp;
732 ipmgmt_getif_rval_t *rvalp;
733 ipmgmt_retval_t rval;
734 ipmgmt_getif_cbarg_t cbarg;
735 ipadm_if_info_t *ifp, *rifp, *curifp;
736 int i, err = 0, count = 0;
737 size_t rbufsize;
739 assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
741 bzero(&cbarg, sizeof (cbarg));
742 cbarg.cb_ifname = getif->ia_ifname;
743 err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
744 if (err == ENOENT && cbarg.cb_ifinfo) {
746 * If there is atleast one entry in the nvlist,
747 * do not return error.
749 err = 0;
751 if (err != 0) {
752 rval.ir_err = err;
753 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
754 return;
757 /* allocate sufficient buffer to return the interface info */
758 for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
759 ++count;
760 rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
761 rvalp = alloca(rbufsize);
762 bzero(rvalp, rbufsize);
764 rvalp->ir_ifcnt = count;
765 rifp = rvalp->ir_ifinfo;
766 ifp = cbarg.cb_ifinfo;
769 * copy the interface info to buffer allocated on stack. The reason
770 * we do this is to avoid memory leak, as door_return() would never
771 * return
773 for (i = 0; i < count; i++) {
774 rifp = rvalp->ir_ifinfo + i;
775 (void) bcopy(ifp, rifp, sizeof (*rifp));
776 rifp->ifi_next = NULL;
777 curifp = ifp->ifi_next;
778 free(ifp);
779 ifp = curifp;
781 rvalp->ir_err = err;
782 (void) door_return((char *)rvalp, rbufsize, NULL, 0);
786 * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
787 * interface configuration (interface properties and addresses), for all those
788 * interfaces that need to be initialized.
790 static void
791 ipmgmt_initif_handler(void *argp)
793 ipmgmt_initif_arg_t *initif = argp;
794 size_t buflen, nvlsize;
795 char *buf = NULL, *onvlbuf, *invlbuf;
796 ipmgmt_get_rval_t rval, *rvalp = &rval;
797 ipmgmt_initif_cbarg_t cbarg;
798 int err;
800 assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
802 bzero(&cbarg, sizeof (cbarg));
803 invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
804 nvlsize = initif->ia_nvlsize;
805 err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
806 if (err != 0)
807 goto fail;
809 cbarg.cb_family = initif->ia_family;
810 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
811 goto fail;
813 err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
814 if (err == ENOENT && cbarg.cb_ocnt > 0) {
816 * If there is atleast one entry in the nvlist,
817 * do not return error.
819 err = 0;
821 if (err != 0)
822 goto fail;
824 if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
825 goto fail;
826 buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
828 * We cannot use malloc() here because door_return never returns, and
829 * memory allocated by malloc() would get leaked. Use alloca() instead.
831 buf = alloca(buflen);
832 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
833 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
834 NV_ENCODE_NATIVE, 0)) != 0) {
835 goto fail;
837 nvlist_free(cbarg.cb_invl);
838 nvlist_free(cbarg.cb_onvl);
839 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
840 rvalp->ir_err = 0;
841 rvalp->ir_nvlsize = nvlsize;
843 (void) door_return(buf, buflen, NULL, 0);
844 return;
845 fail:
846 nvlist_free(cbarg.cb_invl);
847 nvlist_free(cbarg.cb_onvl);
848 rvalp->ir_err = err;
849 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
853 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
855 ipadm_dbwrite_cbarg_t cb;
856 uint32_t flags = sargp->ia_flags;
857 nvlist_t *nvl = NULL;
858 int err = 0;
859 char strval[IPMGMT_STRSIZE];
861 if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
862 sargp->ia_ifname[0] == '\0') {
863 err = EINVAL;
864 goto ret;
866 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
867 goto ret;
868 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
869 sargp->ia_ifname)) != 0)
870 goto ret;
871 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
872 if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
873 goto ret;
874 cb.dbw_nvl = nvl;
875 cb.dbw_flags = 0;
876 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
877 ret:
878 nvlist_free(nvl);
879 return (err);