Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / cmd / cmd-inet / lib / ipmgmtd / ipmgmt_door.c
blob320b32feec9c8319b90d91656c8e04049c537685
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];
121 struct passwd *result;
123 if (door_ucred(&cred) != 0) {
124 err = errno;
125 ipmgmt_log(LOG_ERR, "Could not get user credentials.");
126 goto fail;
128 uid = ucred_getruid(cred);
129 if ((int)uid < 0) {
130 err = errno;
131 ipmgmt_log(LOG_ERR, "Could not get user id.");
132 goto fail;
134 getpwuid_r(uid, &pwd, buf, sizeof (buf), &result);
135 if (!result) {
136 err = errno;
137 ipmgmt_log(LOG_ERR, "Could not get password entry.");
138 goto fail;
140 if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
141 pwd.pw_name) != 1) {
142 err = EPERM;
143 ipmgmt_log(LOG_ERR, "Not authorized for operation.");
144 goto fail;
146 ucred_free(cred);
149 /* individual handlers take care of calling door_return */
150 infop->idi_handler((void *)argp);
151 return;
152 fail:
153 ucred_free(cred);
154 retval.ir_err = err;
155 (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
159 * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
160 * property value for the given property.
162 static void
163 ipmgmt_getprop_handler(void *argp)
165 ipmgmt_prop_arg_t *pargp = argp;
166 ipmgmt_getprop_rval_t rval, *rvalp = &rval;
168 assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
170 rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ);
171 if (rvalp->ir_err == 0)
172 (void) strlcpy(rvalp->ir_pval, pargp->ia_pval,
173 sizeof (rvalp->ir_pval));
174 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
178 * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
179 * for the given property in the DB.
181 static void
182 ipmgmt_setprop_handler(void *argp)
184 ipmgmt_prop_arg_t *pargp = argp;
185 ipmgmt_retval_t rval;
186 ipadm_dbwrite_cbarg_t cb;
187 nvlist_t *nvl = NULL;
188 int err;
190 assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
192 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
193 goto fail;
194 if (pargp->ia_module[0] != '\0' &&
195 (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME,
196 pargp->ia_module)) != 0) {
197 goto fail;
199 if (pargp->ia_ifname[0] != '\0' &&
200 (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
201 pargp->ia_ifname)) != 0)
202 goto fail;
203 if (pargp->ia_aobjname[0] != '\0' &&
204 (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME,
205 pargp->ia_aobjname)) != 0)
206 goto fail;
207 if ((err = nvlist_add_string(nvl, pargp->ia_pname,
208 pargp->ia_pval)) != 0)
209 goto fail;
211 cb.dbw_nvl = nvl;
212 cb.dbw_flags = pargp->ia_flags;
213 err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
214 fail:
215 nvlist_free(nvl);
216 rval.ir_err = err;
217 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
221 * Helper function for ipmgmt_setaddr_handler().
222 * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
224 static int
225 i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
227 char *aobjname = NULL, *ifname = NULL;
228 int32_t lnum;
229 nvlist_t *nvladdr;
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_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvladdr) == 0) {
248 char *reqhost;
250 af = AF_INET;
251 addrtype = IPADM_ADDR_DHCP;
254 * ipmgmt_am_reqhost comes through in `nvl' for purposes of
255 * updating the cached representation, but it is persisted as
256 * a stand-alone DB line; so remove it after copying it.
258 if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) {
259 *nodep->ipmgmt_am_reqhost = '\0';
260 } else {
261 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST,
262 &reqhost)) != 0)
263 return (err);
265 (void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost,
266 sizeof (nodep->ipmgmt_am_reqhost));
267 (void) nvlist_remove(nvl, IPADM_NVP_REQHOST,
268 DATA_TYPE_STRING);
270 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
271 af = AF_INET6;
272 addrtype = IPADM_ADDR_STATIC;
273 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
274 struct sockaddr_in6 sin6 = {0};
275 uint8_t *addr6;
276 uint32_t plen;
277 uint_t n;
279 af = AF_INET6;
280 addrtype = IPADM_ADDR_IPV6_ADDRCONF;
281 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
282 &plen) != 0)
283 return (EINVAL);
284 if (plen != 0) {
285 if (nvlist_lookup_uint8_array(nvladdr,
286 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
287 return (EINVAL);
288 bcopy(addr6, &sin6.sin6_addr, n);
291 nodep->ipmgmt_am_linklocal = B_TRUE;
292 nodep->ipmgmt_am_ifid = sin6;
296 * populate the non-addrtype-specific `*nodep' with retrieved values.
298 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
299 (void) strlcpy(nodep->am_aobjname, aobjname,
300 sizeof (nodep->am_aobjname));
301 nodep->am_lnum = lnum;
302 nodep->am_family = af;
303 nodep->am_atype = addrtype;
304 nodep->am_next = NULL;
307 * Do not store logical interface number in persistent store as it
308 * takes different value on reboot. So remove it from `nvl'.
310 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
311 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
313 return (0);
317 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
318 * node to the list `aobjmap' and optionally persists the address
319 * information in the DB.
321 static void
322 ipmgmt_setaddr_handler(void *argp)
324 ipmgmt_setaddr_arg_t *sargp = argp;
325 ipmgmt_retval_t rval;
326 ipmgmt_aobjmap_t node = {0};
327 nvlist_t *nvl = NULL;
328 char *nvlbuf;
329 size_t nvlsize = sargp->ia_nvlsize;
330 uint32_t flags = sargp->ia_flags;
331 int err = 0;
333 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
334 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
335 goto ret;
336 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
337 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
338 goto ret;
339 if (flags & IPMGMT_INIT)
340 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
341 else
342 node.am_flags = flags & ~IPMGMT_PROPS_ONLY;
343 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
344 goto ret;
346 if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) {
347 ipadm_dbwrite_cbarg_t cb;
349 cb.dbw_nvl = nvl;
350 cb.dbw_flags = 0;
351 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
353 ret:
354 nvlist_free(nvl);
355 rval.ir_err = err;
356 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
360 * Handles the door commands that read or modify the `aobjmap' structure.
362 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
363 * after ensuring that the namespace is not taken. If required, also
364 * generates an `aobjname' for address object for the library to use.
365 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
366 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
367 * associated with that logical interface.
368 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
369 * interface associated with that address object.
371 static void
372 ipmgmt_aobjop_handler(void *argp)
374 ipmgmt_aobjop_arg_t *largp = argp;
375 ipmgmt_retval_t rval;
376 ipmgmt_aobjop_rval_t aobjrval;
377 void *rvalp;
378 size_t rsize;
379 ipmgmt_aobjmap_t node;
380 int err = 0;
381 char *ifname = largp->ia_ifname;
382 char *aobjname = largp->ia_aobjname;
383 int32_t lnum = largp->ia_lnum;
384 sa_family_t af = largp->ia_family;
385 ipadm_addr_type_t atype = largp->ia_atype;
386 ipmgmt_aobjmap_t *head;
388 switch (largp->ia_cmd) {
389 case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
390 rsize = sizeof (ipmgmt_aobjop_rval_t);
391 rvalp = &aobjrval;
392 bzero(&node, sizeof (node));
393 (void) strlcpy(node.am_aobjname, aobjname,
394 sizeof (node.am_aobjname));
395 (void) strlcpy(node.am_ifname, ifname,
396 sizeof (node.am_ifname));
397 node.am_family = af;
398 node.am_atype = atype;
399 /* no logical number is associated with this addrobj yet */
400 node.am_lnum = -1;
401 /* The address object is not persisted yet. */
402 node.am_flags = IPMGMT_ACTIVE;
403 err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
404 if (err == 0) {
405 (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
406 sizeof (aobjrval.ir_aobjname));
408 break;
409 case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
410 rsize = sizeof (ipmgmt_retval_t);
411 rvalp = &rval;
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_family = af;
418 node.am_lnum = lnum;
419 err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
420 break;
421 case IPMGMT_CMD_ADDROBJ_ADD:
422 rsize = sizeof (ipmgmt_retval_t);
423 rvalp = &rval;
424 if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
425 af == AF_UNSPEC) {
426 err = EINVAL;
427 break;
429 bzero(&node, sizeof (node));
430 (void) strlcpy(node.am_aobjname, aobjname,
431 sizeof (node.am_aobjname));
432 (void) strlcpy(node.am_ifname, ifname,
433 sizeof (node.am_ifname));
434 node.am_atype = atype;
435 node.am_lnum = lnum;
436 node.am_family = af;
437 /* The address object is not persisted. */
438 node.am_flags = IPMGMT_ACTIVE;
439 err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
440 break;
441 case IPMGMT_CMD_AOBJNAME2ADDROBJ:
442 rsize = sizeof (ipmgmt_aobjop_rval_t);
443 rvalp = &aobjrval;
444 bzero(&aobjrval, sizeof (aobjrval));
445 if (aobjname[0] == '\0') {
446 err = EINVAL;
447 break;
449 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
450 head = aobjmap.aobjmap_head;
451 for (; head; head = head->am_next) {
452 if (strcmp(head->am_aobjname, aobjname) != 0)
453 continue;
455 * For an auto-configured interface, return
456 * the lifnum that has the link-local on it.
457 * Other logical interfaces were created for
458 * prefixes and dhcpv6 addresses and do not
459 * have am_ifid set.
461 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
462 head->ipmgmt_am_linklocal) {
463 break;
466 if (head == NULL) {
467 err = ENOENT;
468 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
469 break;
471 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
472 sizeof (aobjrval.ir_ifname));
473 aobjrval.ir_lnum = head->am_lnum;
474 aobjrval.ir_family = head->am_family;
475 aobjrval.ir_flags = head->am_flags;
476 aobjrval.ir_atype = head->am_atype;
477 aobjrval.ir_atype_cache = head->am_atype_cache;
478 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
479 break;
480 case IPMGMT_CMD_LIF2ADDROBJ:
481 rsize = sizeof (ipmgmt_aobjop_rval_t);
482 rvalp = &aobjrval;
483 bzero(&aobjrval, sizeof (aobjrval));
484 if (ifname[0] == '\0') {
485 err = EINVAL;
486 break;
488 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
489 head = aobjmap.aobjmap_head;
490 for (; head; head = head->am_next) {
491 if (strcmp(head->am_ifname, ifname) == 0 &&
492 head->am_lnum == lnum &&
493 head->am_family == af) {
494 break;
497 if (head == NULL) {
498 err = ENOENT;
499 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
500 break;
502 (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
503 sizeof (aobjrval.ir_aobjname));
504 aobjrval.ir_atype = head->am_atype;
505 aobjrval.ir_flags = head->am_flags;
506 aobjrval.ir_atype_cache = head->am_atype_cache;
507 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
508 break;
509 default:
510 rsize = sizeof (ipmgmt_retval_t);
511 rvalp = &rval;
512 err = EINVAL;
514 ((ipmgmt_retval_t *)rvalp)->ir_err = err;
515 (void) door_return((char *)rvalp, rsize, NULL, 0);
519 * Given an interface name and family, deletes all the address objects
520 * associated with it.
522 void
523 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
525 ipmgmt_aobjmap_t *head, *next, *prev;
526 ipadm_db_op_t db_op;
528 prev = NULL;
530 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
531 head = aobjmap.aobjmap_head;
532 for (; head; head = next) {
533 next = head->am_next;
534 if (strcmp(head->am_ifname, ifname) != 0 ||
535 head->am_family != af) {
536 prev = head;
537 continue;
540 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
541 flags == IPMGMT_ACTIVE) {
543 * If the addres is present in both active and
544 * persistent store, and if we are performing
545 * a temporary delete, we update the node to
546 * indicate that the address is only present in
547 * persistent store and we proceed. Otherwise
548 * we always delete the node from aobjmap.
550 head->am_flags &= ~IPMGMT_ACTIVE;
551 head->am_lnum = -1;
552 db_op = IPADM_DB_WRITE;
553 } else {
554 db_op = IPADM_DB_DELETE;
555 if (prev == NULL)
556 aobjmap.aobjmap_head = next;
557 else
558 prev->am_next = next;
560 (void) ipmgmt_persist_aobjmap(head, db_op);
561 if (db_op == IPADM_DB_DELETE)
562 free(head);
564 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
568 * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
569 * information in the DB.
571 static void
572 ipmgmt_setif_handler(void *argp)
574 ipmgmt_retval_t rval;
576 rval.ir_err = ipmgmt_persist_if(argp);
577 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
581 * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
582 * deletes all the persisted interface configuration. It also deletes, from
583 * `aobjmap', all the address objects configured on the given interface.
585 static void
586 ipmgmt_resetif_handler(void *argp)
588 ipmgmt_if_arg_t *rargp = argp;
589 ipmgmt_retval_t rval;
590 ipmgmt_if_cbarg_t cbarg;
591 uint32_t flags = rargp->ia_flags;
592 int err = 0;
594 cbarg.cb_family = rargp->ia_family;
595 cbarg.cb_ifname = rargp->ia_ifname;
596 if (flags & IPMGMT_PERSIST)
597 err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
598 IPADM_DB_DELETE);
600 if (flags & IPMGMT_ACTIVE)
601 i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
602 flags);
604 rval.ir_err = err;
605 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
609 * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
610 * deletes all the persisted addrobj configuration. It also deletes the
611 * corresponding node, from `aobjmap'.
613 static void
614 ipmgmt_resetaddr_handler(void *argp)
616 ipmgmt_addr_arg_t *rargp = argp;
617 ipmgmt_retval_t rval;
618 ipmgmt_aobjmap_t node;
619 uint32_t flags = rargp->ia_flags;
620 int err = 0;
621 ipmgmt_resetaddr_cbarg_t cbarg;
623 cbarg.cb_aobjname = rargp->ia_aobjname;
625 if (flags & IPMGMT_PERSIST)
626 err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
627 IPADM_DB_DELETE);
629 if (flags & IPMGMT_ACTIVE) {
630 bzero(&node, sizeof (node));
631 (void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
632 sizeof (node.am_aobjname));
635 * am_lnum is used only for IPv6 autoconf case, since there
636 * can be multiple nodes with the same aobjname.
638 node.am_lnum = rargp->ia_lnum;
639 node.am_flags = flags;
640 (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
643 rval.ir_err = err;
644 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
648 * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
649 * address for a given `gargp->ia_aobjname'. If it is not defined then it
650 * retrieves all the addresses configured on `gargp->ia_ifname'. The
651 * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
652 * handler through library.
654 static void
655 ipmgmt_getaddr_handler(void *argp)
657 size_t buflen, onvlsize;
658 char *buf, *onvlbuf;
659 ipmgmt_getaddr_arg_t *gargp = argp;
660 ipmgmt_getaddr_cbarg_t cbarg;
661 ipmgmt_get_rval_t rval, *rvalp = &rval;
662 int err = 0;
664 cbarg.cb_ifname = gargp->ia_ifname;
665 cbarg.cb_aobjname = gargp->ia_aobjname;
666 cbarg.cb_ocnt = 0;
667 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
668 goto fail;
669 err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
670 if (err == ENOENT && cbarg.cb_ocnt > 0) {
672 * If there is atleast one entry in the nvlist,
673 * do not return error.
675 err = 0;
677 if (err != 0)
678 goto fail;
680 if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
681 NV_ENCODE_NATIVE)) != 0) {
682 goto fail;
684 buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
686 * We cannot use malloc() here because door_return never returns, and
687 * memory allocated by malloc() would get leaked. Use alloca() instead.
689 buf = alloca(buflen);
690 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
691 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
692 NV_ENCODE_NATIVE, 0)) != 0) {
693 goto fail;
695 nvlist_free(cbarg.cb_onvl);
696 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
697 rvalp->ir_err = 0;
698 rvalp->ir_nvlsize = onvlsize;
700 (void) door_return(buf, buflen, NULL, 0);
701 return;
702 fail:
703 nvlist_free(cbarg.cb_onvl);
704 rvalp->ir_err = err;
705 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
709 * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
710 * from the DB.
712 static void
713 ipmgmt_resetprop_handler(void *argp)
715 ipmgmt_prop_arg_t *pargp = argp;
716 ipmgmt_retval_t rval;
718 assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
720 rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
721 IPADM_DB_DELETE);
722 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
726 * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
727 * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
729 static void
730 ipmgmt_getif_handler(void *argp)
732 ipmgmt_getif_arg_t *getif = argp;
733 ipmgmt_getif_rval_t *rvalp;
734 ipmgmt_retval_t rval;
735 ipmgmt_getif_cbarg_t cbarg;
736 ipadm_if_info_t *ifp, *rifp, *curifp;
737 int i, err = 0, count = 0;
738 size_t rbufsize;
740 assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
742 bzero(&cbarg, sizeof (cbarg));
743 cbarg.cb_ifname = getif->ia_ifname;
744 err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
745 if (err == ENOENT && cbarg.cb_ifinfo) {
747 * If there is atleast one entry in the nvlist,
748 * do not return error.
750 err = 0;
752 if (err != 0) {
753 rval.ir_err = err;
754 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
755 return;
758 /* allocate sufficient buffer to return the interface info */
759 for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
760 ++count;
761 rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
762 rvalp = alloca(rbufsize);
763 bzero(rvalp, rbufsize);
765 rvalp->ir_ifcnt = count;
766 rifp = rvalp->ir_ifinfo;
767 ifp = cbarg.cb_ifinfo;
770 * copy the interface info to buffer allocated on stack. The reason
771 * we do this is to avoid memory leak, as door_return() would never
772 * return
774 for (i = 0; i < count; i++) {
775 rifp = rvalp->ir_ifinfo + i;
776 (void) bcopy(ifp, rifp, sizeof (*rifp));
777 rifp->ifi_next = NULL;
778 curifp = ifp->ifi_next;
779 free(ifp);
780 ifp = curifp;
782 rvalp->ir_err = err;
783 (void) door_return((char *)rvalp, rbufsize, NULL, 0);
787 * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
788 * interface configuration (interface properties and addresses), for all those
789 * interfaces that need to be initialized.
791 static void
792 ipmgmt_initif_handler(void *argp)
794 ipmgmt_initif_arg_t *initif = argp;
795 size_t buflen, nvlsize;
796 char *buf = NULL, *onvlbuf, *invlbuf;
797 ipmgmt_get_rval_t rval, *rvalp = &rval;
798 ipmgmt_initif_cbarg_t cbarg;
799 int err;
801 assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
803 bzero(&cbarg, sizeof (cbarg));
804 invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
805 nvlsize = initif->ia_nvlsize;
806 err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
807 if (err != 0)
808 goto fail;
810 cbarg.cb_family = initif->ia_family;
811 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
812 goto fail;
814 err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
815 if (err == ENOENT && cbarg.cb_ocnt > 0) {
817 * If there is atleast one entry in the nvlist,
818 * do not return error.
820 err = 0;
822 if (err != 0)
823 goto fail;
825 if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
826 goto fail;
827 buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
829 * We cannot use malloc() here because door_return never returns, and
830 * memory allocated by malloc() would get leaked. Use alloca() instead.
832 buf = alloca(buflen);
833 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
834 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
835 NV_ENCODE_NATIVE, 0)) != 0) {
836 goto fail;
838 nvlist_free(cbarg.cb_invl);
839 nvlist_free(cbarg.cb_onvl);
840 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
841 rvalp->ir_err = 0;
842 rvalp->ir_nvlsize = nvlsize;
844 (void) door_return(buf, buflen, NULL, 0);
845 return;
846 fail:
847 nvlist_free(cbarg.cb_invl);
848 nvlist_free(cbarg.cb_onvl);
849 rvalp->ir_err = err;
850 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
854 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
856 ipadm_dbwrite_cbarg_t cb;
857 uint32_t flags = sargp->ia_flags;
858 nvlist_t *nvl = NULL;
859 int err = 0;
860 char strval[IPMGMT_STRSIZE];
862 if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
863 sargp->ia_ifname[0] == '\0') {
864 err = EINVAL;
865 goto ret;
867 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
868 goto ret;
869 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
870 sargp->ia_ifname)) != 0)
871 goto ret;
872 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
873 if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
874 goto ret;
875 cb.dbw_nvl = nvl;
876 cb.dbw_flags = 0;
877 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
878 ret:
879 nvlist_free(nvl);
880 return (err);