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