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 (c) 2016, Chris Fraire <cfraire@me.com>.
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 /* 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
122 if (door_ucred(&cred) != 0) {
123 err = errno;
124 ipmgmt_log(LOG_ERR, "Could not get user credentials.");
125 goto fail;
126 }
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;
132 }
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;
138 }
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;
144 }
145 ucred_free(cred);
146 }
147
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);
155 }
156
157 /*
158 * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
159 * property value for the given property.
160 */
161 static void
162 ipmgmt_getprop_handler(void *argp)
163 {
164 ipmgmt_prop_arg_t *pargp = argp;
165 ipmgmt_getprop_rval_t rval, *rvalp = &rval;
166
167 assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
168
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);
174 }
175
176 /*
177 * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
178 * for the given property in the DB.
179 */
180 static void
181 ipmgmt_setprop_handler(void *argp)
182 {
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;
188
189 assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
190
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;
197 }
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;
209
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);
217 }
218
219 /*
220 * Helper function for ipmgmt_setaddr_handler().
221 * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
222 */
223 static int
224 i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
225 {
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;
232
233 /*
234 * Retrieve all the information needed to build '*nodep' from
235 * nvlist_t nvl.
236 */
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);
242 }
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;
248 boolean_t primary;
249
250 af = AF_INET;
251 addrtype = IPADM_ADDR_DHCP;
252
253 if (nvlist_lookup_boolean_value(nvladdr, IPADM_NVP_PRIMARY,
254 &primary) != 0)
255 return (EINVAL);
256 nodep->ipmgmt_am_primary = primary;
257
258 /*
259 * ipmgmt_am_reqhost comes through in `nvl' for purposes of updating
260 * the cached representation, but it is persisted as a stand-alone
261 * DB line; so remove it after copying it.
262 */
263 if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) {
264 *nodep->ipmgmt_am_reqhost = '\0';
265 } else {
266 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST,
267 &reqhost)) != 0)
268 return (err);
269
270 (void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost,
271 sizeof (nodep->ipmgmt_am_reqhost));
272 (void) nvlist_remove(nvl, IPADM_NVP_REQHOST, DATA_TYPE_STRING);
273 }
274 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
275 af = AF_INET6;
276 addrtype = IPADM_ADDR_STATIC;
277 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
278 struct sockaddr_in6 sin6 = {0};
279 uint8_t *addr6;
280 uint32_t plen;
281 uint_t n;
282
283 af = AF_INET6;
284 addrtype = IPADM_ADDR_IPV6_ADDRCONF;
285 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
286 &plen) != 0)
287 return (EINVAL);
288 if (plen != 0) {
289 if (nvlist_lookup_uint8_array(nvladdr,
290 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
291 return (EINVAL);
292 bcopy(addr6, &sin6.sin6_addr, n);
293 }
294
295 nodep->ipmgmt_am_linklocal = B_TRUE;
296 nodep->ipmgmt_am_ifid = sin6;
297 }
298
299 /*
300 * populate the non-addrtype-specific `*nodep' with retrieved values.
301 */
302 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
303 (void) strlcpy(nodep->am_aobjname, aobjname,
304 sizeof (nodep->am_aobjname));
305 nodep->am_lnum = lnum;
306 nodep->am_family = af;
307 nodep->am_atype = addrtype;
308 nodep->am_next = NULL;
309
310 /*
311 * Do not store logical interface number in persistent store as it
312 * takes different value on reboot. So remove it from `nvl'.
313 */
314 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
315 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
316
317 return (0);
318 }
319
320 /*
321 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
322 * node to the list `aobjmap' and optionally persists the address
323 * information in the DB.
324 */
325 static void
326 ipmgmt_setaddr_handler(void *argp)
327 {
328 ipmgmt_setaddr_arg_t *sargp = argp;
329 ipmgmt_retval_t rval;
330 ipmgmt_aobjmap_t node = {0};
331 nvlist_t *nvl = NULL;
332 char *nvlbuf;
333 size_t nvlsize = sargp->ia_nvlsize;
334 uint32_t flags = sargp->ia_flags;
335 int err = 0;
336
337 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
338 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
339 goto ret;
340 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
341 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
342 goto ret;
343 if (flags & IPMGMT_INIT)
344 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
345 else
346 node.am_flags = flags & ~IPMGMT_PROPS_ONLY;
347 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
348 goto ret;
349 }
350 if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) {
351 ipadm_dbwrite_cbarg_t cb;
352
353 cb.dbw_nvl = nvl;
354 cb.dbw_flags = 0;
355 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
356 }
357 ret:
358 nvlist_free(nvl);
359 rval.ir_err = err;
360 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
361 }
362
363 /*
364 * Handles the door commands that read or modify the `aobjmap' structure.
365 *
366 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
367 * after ensuring that the namespace is not taken. If required, also
368 * generates an `aobjname' for address object for the library to use.
369 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
370 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
371 * associated with that logical interface.
372 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
373 * interface associated with that address object.
374 */
375 static void
376 ipmgmt_aobjop_handler(void *argp)
377 {
378 ipmgmt_aobjop_arg_t *largp = argp;
379 ipmgmt_retval_t rval;
380 ipmgmt_aobjop_rval_t aobjrval;
381 void *rvalp;
382 size_t rsize;
383 ipmgmt_aobjmap_t node;
384 int err = 0;
385 char *ifname = largp->ia_ifname;
386 char *aobjname = largp->ia_aobjname;
387 int32_t lnum = largp->ia_lnum;
388 sa_family_t af = largp->ia_family;
389 ipadm_addr_type_t atype = largp->ia_atype;
390 ipmgmt_aobjmap_t *head;
391
392 switch (largp->ia_cmd) {
393 case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
394 rsize = sizeof (ipmgmt_aobjop_rval_t);
395 rvalp = &aobjrval;
396 bzero(&node, sizeof (node));
397 (void) strlcpy(node.am_aobjname, aobjname,
398 sizeof (node.am_aobjname));
399 (void) strlcpy(node.am_ifname, ifname,
400 sizeof (node.am_ifname));
401 node.am_family = af;
402 node.am_atype = atype;
403 /* no logical number is associated with this addrobj yet */
404 node.am_lnum = -1;
405 /* The address object is not persisted yet. */
406 node.am_flags = IPMGMT_ACTIVE;
407 err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
408 if (err == 0) {
409 (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
410 sizeof (aobjrval.ir_aobjname));
411 }
412 break;
413 case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
414 rsize = sizeof (ipmgmt_retval_t);
415 rvalp = &rval;
416 bzero(&node, sizeof (node));
417 (void) strlcpy(node.am_aobjname, aobjname,
418 sizeof (node.am_aobjname));
419 (void) strlcpy(node.am_ifname, ifname,
420 sizeof (node.am_ifname));
421 node.am_family = af;
422 node.am_lnum = lnum;
423 err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
424 break;
425 case IPMGMT_CMD_ADDROBJ_ADD:
426 rsize = sizeof (ipmgmt_retval_t);
427 rvalp = &rval;
428 if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
429 af == AF_UNSPEC) {
430 err = EINVAL;
431 break;
432 }
433 bzero(&node, sizeof (node));
434 (void) strlcpy(node.am_aobjname, aobjname,
435 sizeof (node.am_aobjname));
436 (void) strlcpy(node.am_ifname, ifname,
437 sizeof (node.am_ifname));
438 node.am_atype = atype;
439 node.am_lnum = lnum;
440 node.am_family = af;
441 /* The address object is not persisted. */
442 node.am_flags = IPMGMT_ACTIVE;
443 err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
444 break;
445 case IPMGMT_CMD_AOBJNAME2ADDROBJ:
446 rsize = sizeof (ipmgmt_aobjop_rval_t);
447 rvalp = &aobjrval;
448 bzero(&aobjrval, sizeof (aobjrval));
449 if (aobjname[0] == '\0') {
450 err = EINVAL;
451 break;
452 }
453 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
454 head = aobjmap.aobjmap_head;
455 for (; head; head = head->am_next) {
456 if (strcmp(head->am_aobjname, aobjname) != 0)
457 continue;
458 /*
459 * For an auto-configured interface, return
460 * the lifnum that has the link-local on it.
461 * Other logical interfaces were created for
462 * prefixes and dhcpv6 addresses and do not
463 * have am_ifid set.
464 */
465 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
466 head->ipmgmt_am_linklocal) {
467 break;
468 }
469 }
470 if (head == NULL) {
471 err = ENOENT;
472 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
473 break;
474 }
475 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
476 sizeof (aobjrval.ir_ifname));
477 aobjrval.ir_lnum = head->am_lnum;
478 aobjrval.ir_family = head->am_family;
479 aobjrval.ir_flags = head->am_flags;
480 aobjrval.ir_atype = head->am_atype;
481 (void) memcpy(&aobjrval.ir_atype_cache, &head->am_atype_cache,
482 sizeof (aobjrval.ir_atype_cache));
483 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
484 break;
485 case IPMGMT_CMD_LIF2ADDROBJ:
486 rsize = sizeof (ipmgmt_aobjop_rval_t);
487 rvalp = &aobjrval;
488 bzero(&aobjrval, sizeof (aobjrval));
489 if (ifname[0] == '\0') {
490 err = EINVAL;
491 break;
492 }
493 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
494 head = aobjmap.aobjmap_head;
495 for (; head; head = head->am_next) {
496 if (strcmp(head->am_ifname, ifname) == 0 &&
497 head->am_lnum == lnum &&
498 head->am_family == af) {
499 break;
500 }
501 }
502 if (head == NULL) {
503 err = ENOENT;
504 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
505 break;
506 }
507 (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
508 sizeof (aobjrval.ir_aobjname));
509 aobjrval.ir_atype = head->am_atype;
510 aobjrval.ir_flags = head->am_flags;
511 (void) memcpy(&aobjrval.ir_atype_cache, &head->am_atype_cache,
512 sizeof (aobjrval.ir_atype_cache));
513 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
514 break;
515 default:
516 rsize = sizeof (ipmgmt_retval_t);
517 rvalp = &rval;
518 err = EINVAL;
519 }
520 ((ipmgmt_retval_t *)rvalp)->ir_err = err;
521 (void) door_return((char *)rvalp, rsize, NULL, 0);
522 }
523
524 /*
525 * Given an interface name and family, deletes all the address objects
526 * associated with it.
527 */
528 void
529 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
530 {
531 ipmgmt_aobjmap_t *head, *next, *prev;
532 ipadm_db_op_t db_op;
533
534 prev = NULL;
535
536 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
537 head = aobjmap.aobjmap_head;
538 for (; head; head = next) {
539 next = head->am_next;
540 if (strcmp(head->am_ifname, ifname) != 0 ||
541 head->am_family != af) {
542 prev = head;
543 continue;
544 }
545
546 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
547 flags == IPMGMT_ACTIVE) {
548 /*
549 * If the addres is present in both active and
550 * persistent store, and if we are performing
551 * a temporary delete, we update the node to
552 * indicate that the address is only present in
553 * persistent store and we proceed. Otherwise
554 * we always delete the node from aobjmap.
555 */
556 head->am_flags &= ~IPMGMT_ACTIVE;
557 head->am_lnum = -1;
558 db_op = IPADM_DB_WRITE;
559 } else {
560 db_op = IPADM_DB_DELETE;
561 if (prev == NULL)
562 aobjmap.aobjmap_head = next;
563 else
564 prev->am_next = next;
565 }
566 (void) ipmgmt_persist_aobjmap(head, db_op);
567 if (db_op == IPADM_DB_DELETE)
568 free(head);
569 }
570 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
571 }
572
573 /*
574 * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
575 * information in the DB.
576 */
577 static void
578 ipmgmt_setif_handler(void *argp)
579 {
580 ipmgmt_retval_t rval;
581
582 rval.ir_err = ipmgmt_persist_if(argp);
583 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
584 }
585
586 /*
587 * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
588 * deletes all the persisted interface configuration. It also deletes, from
589 * `aobjmap', all the address objects configured on the given interface.
590 */
591 static void
592 ipmgmt_resetif_handler(void *argp)
593 {
594 ipmgmt_if_arg_t *rargp = argp;
595 ipmgmt_retval_t rval;
596 ipmgmt_if_cbarg_t cbarg;
597 uint32_t flags = rargp->ia_flags;
598 int err = 0;
599
600 cbarg.cb_family = rargp->ia_family;
601 cbarg.cb_ifname = rargp->ia_ifname;
602 if (flags & IPMGMT_PERSIST)
603 err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
604 IPADM_DB_DELETE);
605
606 if (flags & IPMGMT_ACTIVE)
607 i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
608 flags);
609
610 rval.ir_err = err;
611 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
612 }
613
614 /*
615 * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
616 * deletes all the persisted addrobj configuration. It also deletes the
617 * corresponding node, from `aobjmap'.
618 */
619 static void
620 ipmgmt_resetaddr_handler(void *argp)
621 {
622 ipmgmt_addr_arg_t *rargp = argp;
623 ipmgmt_retval_t rval;
624 ipmgmt_aobjmap_t node;
625 uint32_t flags = rargp->ia_flags;
626 int err = 0;
627 ipmgmt_resetaddr_cbarg_t cbarg;
628
629 cbarg.cb_aobjname = rargp->ia_aobjname;
630
631 if (flags & IPMGMT_PERSIST)
632 err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
633 IPADM_DB_DELETE);
634
635 if (flags & IPMGMT_ACTIVE) {
636 bzero(&node, sizeof (node));
637 (void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
638 sizeof (node.am_aobjname));
639
640 /*
641 * am_lnum is used only for IPv6 autoconf case, since there
642 * can be multiple nodes with the same aobjname.
643 */
644 node.am_lnum = rargp->ia_lnum;
645 node.am_flags = flags;
646 (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
647 }
648
649 rval.ir_err = err;
650 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
651 }
652
653 /*
654 * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
655 * address for a given `gargp->ia_aobjname'. If it is not defined then it
656 * retrieves all the addresses configured on `gargp->ia_ifname'. The
657 * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
658 * handler through library.
659 */
660 static void
661 ipmgmt_getaddr_handler(void *argp)
662 {
663 size_t buflen, onvlsize;
664 char *buf, *onvlbuf;
665 ipmgmt_getaddr_arg_t *gargp = argp;
666 ipmgmt_getaddr_cbarg_t cbarg;
667 ipmgmt_get_rval_t rval, *rvalp = &rval;
668 int err = 0;
669
670 cbarg.cb_ifname = gargp->ia_ifname;
671 cbarg.cb_aobjname = gargp->ia_aobjname;
672 cbarg.cb_ocnt = 0;
673 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
674 goto fail;
675 err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
676 if (err == ENOENT && cbarg.cb_ocnt > 0) {
677 /*
678 * If there is atleast one entry in the nvlist,
679 * do not return error.
680 */
681 err = 0;
682 }
683 if (err != 0)
684 goto fail;
685
686 if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
687 NV_ENCODE_NATIVE)) != 0) {
688 goto fail;
689 }
690 buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
691 /*
692 * We cannot use malloc() here because door_return never returns, and
693 * memory allocated by malloc() would get leaked. Use alloca() instead.
694 */
695 buf = alloca(buflen);
696 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
697 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
698 NV_ENCODE_NATIVE, 0)) != 0) {
699 goto fail;
700 }
701 nvlist_free(cbarg.cb_onvl);
702 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
703 rvalp->ir_err = 0;
704 rvalp->ir_nvlsize = onvlsize;
705
706 (void) door_return(buf, buflen, NULL, 0);
707 return;
708 fail:
709 nvlist_free(cbarg.cb_onvl);
710 rvalp->ir_err = err;
711 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
712 }
713
714 /*
715 * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
716 * from the DB.
717 */
718 static void
719 ipmgmt_resetprop_handler(void *argp)
720 {
721 ipmgmt_prop_arg_t *pargp = argp;
722 ipmgmt_retval_t rval;
723
724 assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
725
726 rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
727 IPADM_DB_DELETE);
728 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
729 }
730
731 /*
732 * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
733 * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
734 */
735 static void
736 ipmgmt_getif_handler(void *argp)
737 {
738 ipmgmt_getif_arg_t *getif = argp;
739 ipmgmt_getif_rval_t *rvalp;
740 ipmgmt_retval_t rval;
741 ipmgmt_getif_cbarg_t cbarg;
742 ipadm_if_info_t *ifp, *rifp, *curifp;
743 int i, err = 0, count = 0;
744 size_t rbufsize;
745
746 assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
747
748 bzero(&cbarg, sizeof (cbarg));
749 cbarg.cb_ifname = getif->ia_ifname;
750 err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
751 if (err == ENOENT && cbarg.cb_ifinfo) {
752 /*
753 * If there is atleast one entry in the nvlist,
754 * do not return error.
755 */
756 err = 0;
757 }
758 if (err != 0) {
759 rval.ir_err = err;
760 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
761 return;
762 }
763
764 /* allocate sufficient buffer to return the interface info */
765 for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
766 ++count;
767 rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
768 rvalp = alloca(rbufsize);
769 bzero(rvalp, rbufsize);
770
771 rvalp->ir_ifcnt = count;
772 rifp = rvalp->ir_ifinfo;
773 ifp = cbarg.cb_ifinfo;
774
775 /*
776 * copy the interface info to buffer allocated on stack. The reason
777 * we do this is to avoid memory leak, as door_return() would never
778 * return
779 */
780 for (i = 0; i < count; i++) {
781 rifp = rvalp->ir_ifinfo + i;
782 (void) bcopy(ifp, rifp, sizeof (*rifp));
783 rifp->ifi_next = NULL;
784 curifp = ifp->ifi_next;
785 free(ifp);
786 ifp = curifp;
787 }
788 rvalp->ir_err = err;
789 (void) door_return((char *)rvalp, rbufsize, NULL, 0);
790 }
791
792 /*
793 * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
794 * interface configuration (interface properties and addresses), for all those
795 * interfaces that need to be initialized.
796 */
797 static void
798 ipmgmt_initif_handler(void *argp)
799 {
800 ipmgmt_initif_arg_t *initif = argp;
801 size_t buflen, nvlsize;
802 char *buf = NULL, *onvlbuf, *invlbuf;
803 ipmgmt_get_rval_t rval, *rvalp = &rval;
804 ipmgmt_initif_cbarg_t cbarg;
805 int err;
806
807 assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
808
809 bzero(&cbarg, sizeof (cbarg));
810 invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
811 nvlsize = initif->ia_nvlsize;
812 err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
813 if (err != 0)
814 goto fail;
815
816 cbarg.cb_family = initif->ia_family;
817 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
818 goto fail;
819
820 err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
821 if (err == ENOENT && cbarg.cb_ocnt > 0) {
822 /*
823 * If there is atleast one entry in the nvlist,
824 * do not return error.
825 */
826 err = 0;
827 }
828 if (err != 0)
829 goto fail;
830
831 if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
832 goto fail;
833 buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
834 /*
835 * We cannot use malloc() here because door_return never returns, and
836 * memory allocated by malloc() would get leaked. Use alloca() instead.
837 */
838 buf = alloca(buflen);
839 onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
840 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
841 NV_ENCODE_NATIVE, 0)) != 0) {
842 goto fail;
843 }
844 nvlist_free(cbarg.cb_invl);
845 nvlist_free(cbarg.cb_onvl);
846 rvalp = (ipmgmt_get_rval_t *)(void *)buf;
847 rvalp->ir_err = 0;
848 rvalp->ir_nvlsize = nvlsize;
849
850 (void) door_return(buf, buflen, NULL, 0);
851 return;
852 fail:
853 nvlist_free(cbarg.cb_invl);
854 nvlist_free(cbarg.cb_onvl);
855 rvalp->ir_err = err;
856 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
857 }
858
859 int
860 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
861 {
862 ipadm_dbwrite_cbarg_t cb;
863 uint32_t flags = sargp->ia_flags;
864 nvlist_t *nvl = NULL;
865 int err = 0;
866 char strval[IPMGMT_STRSIZE];
867
868 if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
869 sargp->ia_ifname[0] == '\0') {
870 err = EINVAL;
871 goto ret;
872 }
873 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
874 goto ret;
875 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
876 sargp->ia_ifname)) != 0)
877 goto ret;
878 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
879 if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
880 goto ret;
881 cb.dbw_nvl = nvl;
882 cb.dbw_flags = 0;
883 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
884 ret:
885 nvlist_free(nvl);
886 return (err);
887 }