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