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