Print this page
Commit IPMP changes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libipadm/common/ipadm_addr.c
+++ new/usr/src/lib/libipadm/common/ipadm_addr.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 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright (c) 2013 by Delphix. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * This file contains functions for address management such as creating
28 28 * an address, deleting an address, enabling an address, disabling an
29 29 * address, bringing an address down or up, setting/getting properties
30 30 * on an address object and listing address information
31 31 * for all addresses in active as well as persistent configuration.
32 32 */
33 33 #include <sys/types.h>
34 34 #include <sys/socket.h>
35 35 #include <netdb.h>
36 36 #include <inet/ip.h>
37 37 #include <string.h>
38 38 #include <strings.h>
39 39 #include <assert.h>
40 40 #include <sys/sockio.h>
41 41 #include <errno.h>
42 42 #include <unistd.h>
43 43 #include <stropts.h>
44 44 #include <zone.h>
45 45 #include <netinet/in.h>
46 46 #include <arpa/inet.h>
47 47 #include <fcntl.h>
48 48 #include <ctype.h>
49 49 #include <dhcpagent_util.h>
50 50 #include <dhcpagent_ipc.h>
51 51 #include <ipadm_ndpd.h>
52 52 #include <libdladm.h>
53 53 #include <libdllink.h>
54 54 #include <libdliptun.h>
55 55 #include <ifaddrs.h>
56 56 #include "libipadm_impl.h"
57 57
58 58 #define SIN6(a) ((struct sockaddr_in6 *)a)
59 59 #define SIN(a) ((struct sockaddr_in *)a)
60 60
61 61 static ipadm_status_t i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
62 62 uint32_t);
63 63 static ipadm_status_t i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
64 64 uint32_t);
65 65 static ipadm_status_t i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
66 66 boolean_t);
67 67 static ipadm_status_t i_ipadm_get_db_addr(ipadm_handle_t, const char *,
68 68 const char *, nvlist_t **);
69 69 static ipadm_status_t i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
70 70 int *);
71 71 static ipadm_status_t i_ipadm_validate_create_addr(ipadm_handle_t,
72 72 ipadm_addrobj_t, uint32_t);
73 73 static ipadm_status_t i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
74 74 uint32_t);
75 75 static ipadm_status_t i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
76 76 uint32_t *);
77 77 static ipadm_status_t i_ipadm_get_static_addr_db(ipadm_handle_t,
78 78 ipadm_addrobj_t);
79 79 static boolean_t i_ipadm_is_user_aobjname_valid(const char *);
80 80
81 81 /*
82 82 * Callback functions to retrieve property values from the kernel. These
83 83 * functions, when required, translate the values from the kernel to a format
84 84 * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
85 85 * for a given property.
86 86 */
87 87 static ipadm_pd_getf_t i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
88 88 i_ipadm_get_zone, i_ipadm_get_broadcast;
89 89
90 90 /*
91 91 * Callback functions to set property values. These functions translate the
92 92 * values to a format suitable for kernel consumption, allocate the necessary
93 93 * ioctl buffers and then invoke ioctl().
94 94 */
95 95 static ipadm_pd_setf_t i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
96 96 i_ipadm_set_zone;
97 97
98 98 /* address properties description table */
99 99 ipadm_prop_desc_t ipadm_addrprop_table[] = {
100 100 { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
101 101 NULL, NULL, i_ipadm_get_broadcast },
102 102
103 103 { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
104 104 i_ipadm_set_addr_flag, i_ipadm_get_onoff,
105 105 i_ipadm_get_addr_flag },
106 106
107 107 { "prefixlen", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
108 108 i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
109 109 i_ipadm_get_prefixlen },
110 110
111 111 { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
112 112 i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
113 113
114 114 { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
115 115 i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
116 116
117 117 { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
118 118 i_ipadm_set_zone, NULL, i_ipadm_get_zone },
119 119
120 120 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
121 121 };
122 122
123 123 static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
124 124 MOD_PROTO_NONE, 0, NULL, NULL, NULL };
125 125
126 126 /*
127 127 * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
128 128 * `ipadm_atype' fields of the given `ipaddr'.
129 129 */
130 130 void
131 131 i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
132 132 const char *aobjname, ipadm_addr_type_t atype)
133 133 {
134 134 bzero(ipaddr, sizeof (struct ipadm_addrobj_s));
135 135 (void) strlcpy(ipaddr->ipadm_ifname, ifname,
136 136 sizeof (ipaddr->ipadm_ifname));
137 137 (void) strlcpy(ipaddr->ipadm_aobjname, aobjname,
138 138 sizeof (ipaddr->ipadm_aobjname));
139 139 ipaddr->ipadm_atype = atype;
140 140 }
141 141
142 142 /*
143 143 * Determine the permission of the property depending on whether it has a
144 144 * set() and/or get() callback functions.
145 145 */
146 146 static ipadm_status_t
147 147 i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize)
148 148 {
149 149 uint_t perm;
150 150 size_t nbytes;
151 151
152 152 perm = 0;
153 153 if (pdp->ipd_set != NULL)
154 154 perm |= MOD_PROP_PERM_WRITE;
155 155 if (pdp->ipd_get != NULL)
156 156 perm |= MOD_PROP_PERM_READ;
157 157
158 158 nbytes = snprintf(buf, *bufsize, "%c%c",
159 159 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
160 160 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
161 161
162 162 if (nbytes >= *bufsize) {
163 163 /* insufficient buffer space */
164 164 *bufsize = nbytes + 1;
165 165 return (IPADM_NO_BUFS);
166 166 }
167 167 return (IPADM_SUCCESS);
168 168 }
169 169
170 170 /*
171 171 * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj()
172 172 * retrieves the information necessary for any operation on the object,
173 173 * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr,
174 174 * refresh-addr, get-addrprop or set-addrprop. The information include
175 175 * the logical interface number, address type, address family,
176 176 * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and
177 177 * the ipadm_flags that indicate if the address is present in
178 178 * active configuration or persistent configuration or both. If the address
179 179 * is not found, IPADM_NOTSUP is returned.
180 180 */
181 181 ipadm_status_t
182 182 i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
183 183 {
184 184 ipmgmt_aobjop_arg_t larg;
185 185 ipmgmt_aobjop_rval_t rval, *rvalp;
186 186 int err = 0;
187 187
188 188 /* populate the door_call argument structure */
189 189 larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
190 190 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
191 191 sizeof (larg.ia_aobjname));
192 192
193 193 rvalp = &rval;
194 194 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
195 195 sizeof (rval), B_FALSE);
196 196 if (err != 0)
197 197 return (ipadm_errno2status(err));
198 198 (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
199 199 sizeof (ipaddr->ipadm_ifname));
200 200 ipaddr->ipadm_lifnum = rval.ir_lnum;
201 201 ipaddr->ipadm_atype = rval.ir_atype;
202 202 ipaddr->ipadm_af = rval.ir_family;
203 203 ipaddr->ipadm_flags = rval.ir_flags;
204 204 if (rval.ir_atype == IPADM_ADDR_IPV6_ADDRCONF) {
205 205 (void) memcpy(&ipaddr->ipadm_intfid, &rval.ir_ifid,
206 206 sizeof (ipaddr->ipadm_intfid));
207 207 }
208 208
209 209 return (IPADM_SUCCESS);
210 210 }
211 211
212 212 /*
213 213 * Retrieves the static address (IPv4 or IPv6) for the given address object
214 214 * in `ipaddr' from persistent DB.
215 215 */
216 216 static ipadm_status_t
217 217 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
218 218 {
219 219 ipadm_status_t status;
220 220 nvlist_t *onvl;
221 221 nvlist_t *anvl = NULL;
222 222 nvlist_t *nvladdr;
↓ open down ↓ |
222 lines elided |
↑ open up ↑ |
223 223 nvpair_t *nvp;
224 224 char *name;
225 225 char *aobjname = ipaddr->ipadm_aobjname;
226 226 char *sname;
227 227 sa_family_t af = AF_UNSPEC;
228 228
229 229 /*
230 230 * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
231 231 */
232 232 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
233 - if (status != IPADM_SUCCESS)
233 + if (status != IPADM_SUCCESS) {
234 234 return (status);
235 + }
235 236 /*
236 237 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
237 238 * or the IPADM_NVP_IPV6ADDR name-value pair.
238 239 */
239 240 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
240 241 nvp = nvlist_next_nvpair(onvl, NULL)) {
241 242 if (nvpair_value_nvlist(nvp, &anvl) != 0)
242 243 continue;
243 244 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
244 245 nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
245 246 break;
246 247 }
247 248 if (nvp == NULL)
248 249 goto fail;
249 250 for (nvp = nvlist_next_nvpair(anvl, NULL);
250 251 nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
251 252 name = nvpair_name(nvp);
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
252 253 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
253 254 af = AF_INET;
254 255 break;
255 256 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
256 257 af = AF_INET6;
257 258 break;
258 259 }
259 260 }
260 261 assert(af != AF_UNSPEC);
261 262 if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
262 - nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
263 - ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
263 + nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0)
264 264 goto fail;
265 +
266 + if (ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
267 + goto fail;
265 268 }
266 269 nvlist_free(onvl);
267 270 return (IPADM_SUCCESS);
268 271 fail:
269 272 nvlist_free(onvl);
270 273 return (IPADM_NOTFOUND);
271 274 }
272 275
273 276 /*
274 277 * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
275 278 * fills in the address objname, the address type and the ipadm_flags.
276 279 */
277 280 ipadm_status_t
278 281 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
279 282 {
280 283 ipmgmt_aobjop_arg_t larg;
281 284 ipmgmt_aobjop_rval_t rval, *rvalp;
282 285 int err;
283 286
284 287 larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
285 288 (void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,
286 289 sizeof (larg.ia_ifname));
287 290 larg.ia_lnum = addrobj->ipadm_lifnum;
288 291 larg.ia_family = addrobj->ipadm_af;
289 292
290 293 rvalp = &rval;
291 294 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
292 295 sizeof (rval), B_FALSE);
293 296 if (err != 0)
294 297 return (ipadm_errno2status(err));
295 298 (void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname,
296 299 sizeof (addrobj->ipadm_aobjname));
297 300 addrobj->ipadm_atype = rval.ir_atype;
298 301 addrobj->ipadm_flags = rval.ir_flags;
299 302
300 303 return (IPADM_SUCCESS);
301 304 }
302 305
303 306 /*
304 307 * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration).
305 308 * with the given name and logical interface number.
306 309 * This API is called by in.ndpd to add addrobjs when new prefixes or
307 310 * dhcpv6 addresses are configured.
308 311 */
309 312 ipadm_status_t
310 313 ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
311 314 const char *aobjname, ipadm_addr_type_t atype, int lnum)
312 315 {
313 316 ipmgmt_aobjop_arg_t larg;
314 317 int err;
315 318
316 319 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD;
317 320 (void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname));
318 321 (void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname));
319 322 larg.ia_atype = atype;
320 323 larg.ia_lnum = lnum;
321 324 larg.ia_family = af;
322 325 err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE);
323 326 return (ipadm_errno2status(err));
324 327 }
325 328
326 329 /*
327 330 * Deletes an address object with given name and logical number from ipmgmtd
328 331 * daemon's aobjmap (active configuration). This API is called by in.ndpd to
329 332 * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
330 333 * removed.
331 334 */
332 335 ipadm_status_t
333 336 ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
334 337 const char *aobjname, ipadm_addr_type_t atype, int lnum)
335 338 {
336 339 struct ipadm_addrobj_s aobj;
337 340
338 341 i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
339 342 aobj.ipadm_af = af;
340 343 aobj.ipadm_lifnum = lnum;
341 344 return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
342 345 }
343 346
344 347 /*
345 348 * Gets all the addresses from active configuration and populates the
346 349 * address information in `addrinfo'.
347 350 */
348 351 static ipadm_status_t
349 352 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
350 353 ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
351 354 {
352 355 ipadm_status_t status;
353 356 struct ifaddrs *ifap, *ifa;
354 357 ipadm_addr_info_t *curr, *prev = NULL;
355 358 struct ifaddrs *cifaddr;
356 359 struct lifreq lifr;
357 360 int sock;
358 361 uint64_t flags;
359 362 char cifname[LIFNAMSIZ];
360 363 struct sockaddr_in6 *sin6;
361 364 struct ipadm_addrobj_s ipaddr;
362 365 char *sep;
363 366 int lnum;
364 367
365 368 retry:
366 369 *addrinfo = NULL;
367 370
368 371 /* Get all the configured addresses */
369 372 if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0)
370 373 return (ipadm_errno2status(errno));
371 374 /* Return if there is nothing to process. */
372 375 if (ifa == NULL)
373 376 return (IPADM_SUCCESS);
374 377 bzero(&lifr, sizeof (lifr));
375 378 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
376 379 struct sockaddr_storage data;
377 380
378 381 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
379 382 lnum = 0;
380 383 if ((sep = strrchr(cifname, ':')) != NULL) {
381 384 *sep++ = '\0';
382 385 lnum = atoi(sep);
383 386 }
384 387 if (ifname != NULL && strcmp(cifname, ifname) != 0)
385 388 continue;
386 389 if (!(ipadm_flags & IPADM_OPT_ZEROADDR) &&
387 390 sockaddrunspec(ifap->ifa_addr) &&
388 391 !(ifap->ifa_flags & IFF_DHCPRUNNING))
389 392 continue;
390 393
391 394 /* Allocate and populate the current node in the list. */
392 395 if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL)
393 396 goto fail;
394 397
395 398 /* Link to the list in `addrinfo'. */
396 399 if (prev != NULL)
397 400 prev->ia_ifa.ifa_next = &curr->ia_ifa;
398 401 else
399 402 *addrinfo = curr;
400 403 prev = curr;
401 404
402 405 cifaddr = &curr->ia_ifa;
403 406 if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL)
404 407 goto fail;
405 408 cifaddr->ifa_flags = ifap->ifa_flags;
406 409 cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
407 410 if (cifaddr->ifa_addr == NULL)
408 411 goto fail;
409 412 (void) memcpy(cifaddr->ifa_addr, ifap->ifa_addr,
410 413 sizeof (struct sockaddr_storage));
411 414 cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
412 415 if (cifaddr->ifa_netmask == NULL)
413 416 goto fail;
414 417 (void) memcpy(cifaddr->ifa_netmask, ifap->ifa_netmask,
415 418 sizeof (struct sockaddr_storage));
416 419 if (ifap->ifa_flags & IFF_POINTOPOINT) {
417 420 cifaddr->ifa_dstaddr = malloc(
418 421 sizeof (struct sockaddr_storage));
419 422 if (cifaddr->ifa_dstaddr == NULL)
420 423 goto fail;
421 424 (void) memcpy(cifaddr->ifa_dstaddr, ifap->ifa_dstaddr,
422 425 sizeof (struct sockaddr_storage));
423 426 } else if (ifap->ifa_flags & IFF_BROADCAST) {
424 427 cifaddr->ifa_broadaddr = malloc(
425 428 sizeof (struct sockaddr_storage));
426 429 if (cifaddr->ifa_broadaddr == NULL)
427 430 goto fail;
428 431 (void) memcpy(cifaddr->ifa_broadaddr,
429 432 ifap->ifa_broadaddr,
430 433 sizeof (struct sockaddr_storage));
431 434 }
432 435 /* Get the addrobj name stored for this logical interface. */
433 436 ipaddr.ipadm_aobjname[0] = '\0';
434 437 (void) strlcpy(ipaddr.ipadm_ifname, cifname,
435 438 sizeof (ipaddr.ipadm_ifname));
436 439 ipaddr.ipadm_lifnum = lnum;
437 440 ipaddr.ipadm_af = ifap->ifa_addr->sa_family;
438 441 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
439 442
440 443 /*
441 444 * Find address type from ifa_flags, if we could not get it
442 445 * from daemon.
443 446 */
444 447 (void) memcpy(&data, ifap->ifa_addr,
445 448 sizeof (struct sockaddr_in6));
446 449 sin6 = SIN6(&data);
447 450 flags = ifap->ifa_flags;
448 451 if (status == IPADM_SUCCESS) {
449 452 (void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname,
450 453 sizeof (curr->ia_aobjname));
451 454 curr->ia_atype = ipaddr.ipadm_atype;
452 455 } else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) ||
453 456 !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
454 457 curr->ia_atype = IPADM_ADDR_DHCP;
455 458 } else if (flags & IFF_ADDRCONF) {
456 459 curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF;
457 460 } else {
458 461 curr->ia_atype = IPADM_ADDR_STATIC;
459 462 }
460 463 /*
461 464 * Populate the flags for the active configuration from the
462 465 * `ifa_flags'.
463 466 */
464 467 if (!(flags & IFF_UP)) {
465 468 if (flags & IFF_DUPLICATE)
466 469 curr->ia_state = IFA_DUPLICATE;
467 470 else
468 471 curr->ia_state = IFA_DOWN;
469 472 } else {
470 473 curr->ia_cflags |= IA_UP;
471 474 if (flags & IFF_RUNNING) {
472 475 (void) strlcpy(lifr.lifr_name, ifap->ifa_name,
473 476 sizeof (lifr.lifr_name));
474 477 sock = (ifap->ifa_addr->sa_family == AF_INET) ?
475 478 iph->iph_sock : iph->iph_sock6;
476 479 if (ioctl(sock, SIOCGLIFDADSTATE,
477 480 (caddr_t)&lifr) < 0) {
478 481 if (errno == ENXIO) {
479 482 freeifaddrs(ifa);
480 483 ipadm_free_addr_info(*addrinfo);
481 484 goto retry;
482 485 }
483 486 goto fail;
484 487 }
485 488 if (lifr.lifr_dadstate == DAD_IN_PROGRESS)
486 489 curr->ia_state = IFA_TENTATIVE;
487 490 else
488 491 curr->ia_state = IFA_OK;
489 492 } else {
490 493 curr->ia_state = IFA_INACCESSIBLE;
491 494 }
492 495 }
493 496 if (flags & IFF_UNNUMBERED)
494 497 curr->ia_cflags |= IA_UNNUMBERED;
495 498 if (flags & IFF_PRIVATE)
496 499 curr->ia_cflags |= IA_PRIVATE;
497 500 if (flags & IFF_TEMPORARY)
498 501 curr->ia_cflags |= IA_TEMPORARY;
499 502 if (flags & IFF_DEPRECATED)
500 503 curr->ia_cflags |= IA_DEPRECATED;
501 504
502 505 }
503 506
504 507 freeifaddrs(ifa);
505 508 return (IPADM_SUCCESS);
506 509
507 510 fail:
508 511 /* On error, cleanup everything and return. */
509 512 ipadm_free_addr_info(*addrinfo);
510 513 *addrinfo = NULL;
511 514 freeifaddrs(ifa);
512 515 return (ipadm_errno2status(errno));
513 516 }
514 517
515 518 /*
516 519 * From the given `name', i_ipadm_name2atype() deduces the address type
517 520 * and address family. If the `name' implies an address, it returns B_TRUE.
518 521 * Else, returns B_FALSE and leaves the output parameters unchanged.
519 522 */
520 523 boolean_t
521 524 i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type)
522 525 {
523 526 boolean_t is_addr = B_TRUE;
524 527
525 528 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
526 529 *af = AF_INET;
527 530 *type = IPADM_ADDR_STATIC;
528 531 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
529 532 *af = AF_INET6;
530 533 *type = IPADM_ADDR_STATIC;
531 534 } else if (strcmp(name, IPADM_NVP_DHCP) == 0) {
532 535 *af = AF_INET;
533 536 *type = IPADM_ADDR_DHCP;
534 537 } else if (strcmp(name, IPADM_NVP_INTFID) == 0) {
535 538 *af = AF_INET6;
536 539 *type = IPADM_ADDR_IPV6_ADDRCONF;
537 540 } else {
538 541 is_addr = B_FALSE;
539 542 }
540 543
541 544 return (is_addr);
542 545 }
543 546
544 547 /*
545 548 * Parses the given nvlist `nvl' for an address or an address property.
546 549 * The input nvlist must contain either an address or an address property.
547 550 * `ainfo' is an input as well as output parameter. When an address or an
548 551 * address property is found, `ainfo' is updated with the information found.
549 552 * Some of the fields may be already filled in by the calling function.
550 553 *
551 554 * The fields that will be filled/updated by this function are `ia_pflags',
552 555 * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl'
553 556 * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are
554 557 * obtained if `nvl' contains an address.
555 558 */
556 559 static ipadm_status_t
557 560 i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
558 561 {
559 562 nvlist_t *nvladdr;
560 563 char *name;
561 564 char *propstr = NULL;
562 565 char *sname, *dname;
563 566 nvpair_t *nvp;
564 567 sa_family_t af;
565 568 ipadm_addr_type_t atype;
566 569 boolean_t is_addr = B_FALSE;
567 570 int err;
568 571
569 572 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
570 573 nvp = nvlist_next_nvpair(nvl, nvp)) {
571 574 name = nvpair_name(nvp);
572 575 if (i_ipadm_name2atype(name, &af, &atype)) {
573 576 err = nvpair_value_nvlist(nvp, &nvladdr);
574 577 is_addr = B_TRUE;
575 578 } else if (IPADM_PRIV_NVP(name)) {
576 579 continue;
577 580 } else {
578 581 err = nvpair_value_string(nvp, &propstr);
579 582 }
580 583 if (err != 0)
581 584 return (ipadm_errno2status(err));
582 585 }
583 586
584 587 if (is_addr) {
585 588 /*
586 589 * We got an address from the nvlist `nvl'.
587 590 * Parse `nvladdr' and populate relevant information
588 591 * in `ainfo'.
589 592 */
590 593 switch (atype) {
591 594 case IPADM_ADDR_STATIC:
592 595 if (strcmp(name, "up") == 0 &&
593 596 strcmp(propstr, "yes") == 0) {
594 597 ainfo->ia_pflags |= IA_UP;
595 598 }
596 599 /*
597 600 * For static addresses, we need to get the hostnames.
598 601 */
599 602 err = nvlist_lookup_string(nvladdr,
600 603 IPADM_NVP_IPADDRHNAME, &sname);
601 604 if (err != 0)
602 605 return (ipadm_errno2status(err));
603 606 (void) strlcpy(ainfo->ia_sname, sname,
604 607 sizeof (ainfo->ia_sname));
605 608 err = nvlist_lookup_string(nvladdr,
606 609 IPADM_NVP_IPDADDRHNAME, &dname);
607 610 if (err == 0) {
608 611 (void) strlcpy(ainfo->ia_dname, dname,
609 612 sizeof (ainfo->ia_dname));
610 613 }
611 614 break;
612 615 case IPADM_ADDR_DHCP:
613 616 case IPADM_ADDR_IPV6_ADDRCONF:
614 617 /*
615 618 * dhcp and addrconf address objects are always
616 619 * marked up when re-enabled.
617 620 */
618 621 ainfo->ia_pflags |= IA_UP;
619 622 break;
620 623 default:
621 624 return (IPADM_FAILURE);
622 625 }
623 626 } else {
624 627 /*
625 628 * We got an address property from `nvl'. Parse the
626 629 * name and the property value. Update the `ainfo->ia_pflags'
627 630 * for the flags.
628 631 */
629 632 if (strcmp(name, "deprecated") == 0) {
630 633 if (strcmp(propstr, IPADM_ONSTR) == 0)
631 634 ainfo->ia_pflags |= IA_DEPRECATED;
632 635 } else if (strcmp(name, "private") == 0) {
633 636 if (strcmp(propstr, IPADM_ONSTR) == 0)
634 637 ainfo->ia_pflags |= IA_PRIVATE;
635 638 }
636 639 }
637 640
638 641 return (IPADM_SUCCESS);
639 642 }
640 643
641 644 /*
642 645 * Parses the given nvlist `nvl' for an address or an address property.
643 646 * The input nvlist must contain either an address or an address property.
644 647 * `ainfo' is an input as well as output parameter. When an address or an
645 648 * address property is found, `ainfo' is updated with the information found.
646 649 * Some of the fields may be already filled in by the calling function,
647 650 * because of previous calls to i_ipadm_nvl2ainfo_active().
648 651 *
649 652 * Since the address object in `nvl' is also in the active configuration, the
650 653 * fields that will be filled/updated by this function are `ia_pflags',
651 654 * `ia_sname' and `ia_dname'.
652 655 *
653 656 * If this function returns an error, the calling function will take
654 657 * care of freeing the fields in `ainfo'.
655 658 */
656 659 static ipadm_status_t
657 660 i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
658 661 {
659 662 return (i_ipadm_nvl2ainfo_common(nvl, ainfo));
660 663 }
661 664
662 665 /*
663 666 * Parses the given nvlist `nvl' for an address or an address property.
664 667 * The input nvlist must contain either an address or an address property.
665 668 * `ainfo' is an input as well as output parameter. When an address or an
666 669 * address property is found, `ainfo' is updated with the information found.
667 670 * Some of the fields may be already filled in by the calling function,
668 671 * because of previous calls to i_ipadm_nvl2ainfo_persist().
669 672 *
670 673 * All the relevant fields in `ainfo' will be filled by this function based
671 674 * on what we find in `nvl'.
672 675 *
673 676 * If this function returns an error, the calling function will take
674 677 * care of freeing the fields in `ainfo'.
675 678 */
676 679 static ipadm_status_t
677 680 i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
678 681 {
679 682 nvlist_t *nvladdr;
680 683 struct ifaddrs *ifa;
681 684 char *name;
682 685 char *ifname = NULL;
683 686 char *aobjname = NULL;
684 687 char *propstr = NULL;
685 688 nvpair_t *nvp;
686 689 sa_family_t af;
687 690 ipadm_addr_type_t atype;
688 691 boolean_t is_addr = B_FALSE;
689 692 size_t size = sizeof (struct sockaddr_storage);
690 693 uint32_t plen = 0;
691 694 int err;
692 695 ipadm_status_t status;
693 696
694 697 status = i_ipadm_nvl2ainfo_common(nvl, ainfo);
695 698 if (status != IPADM_SUCCESS)
696 699 return (status);
697 700
698 701 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
699 702 nvp = nvlist_next_nvpair(nvl, nvp)) {
700 703 name = nvpair_name(nvp);
701 704 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
702 705 err = nvpair_value_string(nvp, &ifname);
703 706 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
704 707 err = nvpair_value_string(nvp, &aobjname);
705 708 } else if (i_ipadm_name2atype(name, &af, &atype)) {
706 709 err = nvpair_value_nvlist(nvp, &nvladdr);
707 710 is_addr = B_TRUE;
708 711 } else {
709 712 err = nvpair_value_string(nvp, &propstr);
710 713 }
711 714 if (err != 0)
712 715 return (ipadm_errno2status(err));
713 716 }
714 717
715 718 ifa = &ainfo->ia_ifa;
716 719 (void) strlcpy(ainfo->ia_aobjname, aobjname,
717 720 sizeof (ainfo->ia_aobjname));
718 721 if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL)
719 722 return (IPADM_NO_MEMORY);
720 723 if (is_addr) {
721 724 struct sockaddr_in6 data;
722 725
723 726 /*
724 727 * We got an address from the nvlist `nvl'.
725 728 * Parse `nvladdr' and populate `ifa->ifa_addr'.
726 729 */
727 730 ainfo->ia_atype = atype;
728 731 if ((ifa->ifa_addr = calloc(1, size)) == NULL)
729 732 return (IPADM_NO_MEMORY);
730 733 switch (atype) {
731 734 case IPADM_ADDR_STATIC:
732 735 ifa->ifa_addr->sa_family = af;
733 736 break;
734 737 case IPADM_ADDR_DHCP:
735 738 ifa->ifa_addr->sa_family = AF_INET;
736 739 break;
737 740 case IPADM_ADDR_IPV6_ADDRCONF:
738 741 data.sin6_family = AF_INET6;
739 742 if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR,
740 743 &data.sin6_addr) != IPADM_SUCCESS)
741 744 return (IPADM_NO_MEMORY);
742 745 err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
743 746 &plen);
744 747 if (err != 0)
745 748 return (ipadm_errno2status(err));
746 749 if ((ifa->ifa_netmask = malloc(size)) == NULL)
747 750 return (IPADM_NO_MEMORY);
748 751 if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0)
749 752 return (ipadm_errno2status(err));
750 753 (void) memcpy(ifa->ifa_addr, &data, sizeof (data));
751 754 break;
752 755 default:
753 756 return (IPADM_FAILURE);
754 757 }
755 758 } else {
756 759 if (strcmp(name, "prefixlen") == 0) {
757 760 /*
758 761 * If a prefixlen was found, update the
759 762 * `ainfo->ia_ifa.ifa_netmask'.
760 763 */
761 764
762 765 if ((ifa->ifa_netmask = malloc(size)) == NULL)
763 766 return (IPADM_NO_MEMORY);
764 767 /*
765 768 * Address property lines always follow the address
766 769 * line itself in the persistent db. We must have
767 770 * found a valid `ainfo->ia_ifa.ifa_addr' by now.
768 771 */
769 772 assert(ifa->ifa_addr != NULL);
770 773 err = plen2mask(atoi(propstr), ifa->ifa_addr->sa_family,
771 774 ifa->ifa_netmask);
772 775 if (err != 0)
773 776 return (ipadm_errno2status(err));
774 777 }
775 778 }
776 779
777 780 return (IPADM_SUCCESS);
778 781 }
779 782
780 783 /*
781 784 * Retrieves all addresses from active config and appends to it the
782 785 * addresses that are found only in persistent config. In addition,
783 786 * it updates the persistent fields for each address from information
784 787 * found in persistent config. The output parameter `addrinfo' contains
785 788 * complete information regarding all addresses in active as well as
786 789 * persistent config.
787 790 */
788 791 static ipadm_status_t
789 792 i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname,
790 793 ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
791 794 {
792 795 nvlist_t *nvladdr = NULL;
793 796 nvlist_t *onvl = NULL;
794 797 nvpair_t *nvp;
795 798 ipadm_status_t status;
796 799 ipadm_addr_info_t *ainfo = NULL;
797 800 ipadm_addr_info_t *curr;
798 801 ipadm_addr_info_t *last = NULL;
799 802 char *aobjname;
800 803
801 804 /* Get all addresses from active config. */
802 805 status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags,
803 806 lifc_flags);
804 807 if (status != IPADM_SUCCESS)
805 808 goto fail;
806 809
807 810 /* Get all addresses from persistent config. */
808 811 status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl);
809 812 /*
810 813 * If no address was found in persistent config, just
811 814 * return what we found in active config.
812 815 */
813 816 if (status == IPADM_NOTFOUND) {
814 817 /*
815 818 * If nothing was found neither active nor persistent
816 819 * config, this means that the interface does not exist,
817 820 * if one was provided in `ifname'.
818 821 */
819 822 if (ainfo == NULL && ifname != NULL)
820 823 return (IPADM_ENXIO);
821 824 *addrinfo = ainfo;
822 825 return (IPADM_SUCCESS);
823 826 }
824 827 /* In case of any other error, cleanup and return. */
825 828 if (status != IPADM_SUCCESS)
826 829 goto fail;
827 830 /* we append to make sure, loopback addresses are first */
828 831 if (ainfo != NULL) {
829 832 for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr))
830 833 ;
831 834 last = curr;
832 835 }
833 836
834 837 /*
835 838 * `onvl' will contain all the address lines from the db. Each line
836 839 * could contain the address itself or an address property. Addresses
837 840 * and address properties are found in separate lines.
838 841 *
839 842 * If an address A was found in active, we will already have `ainfo',
840 843 * and it is present in persistent configuration as well, we need to
841 844 * update `ainfo' with persistent information (`ia_pflags).
842 845 * For each address B found only in persistent configuration,
843 846 * append the address to the list with the address info for B from
844 847 * `onvl'.
845 848 */
846 849 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
847 850 nvp = nvlist_next_nvpair(onvl, nvp)) {
848 851 if (nvpair_value_nvlist(nvp, &nvladdr) != 0)
849 852 continue;
850 853 if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME,
851 854 &aobjname) != 0)
852 855 continue;
853 856 for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) {
854 857 if (strcmp(curr->ia_aobjname, aobjname) == 0)
855 858 break;
856 859 }
857 860 if (curr == NULL) {
858 861 /*
859 862 * We did not find this address object in `ainfo'.
860 863 * This means that the address object exists only
861 864 * in the persistent configuration. Get its
862 865 * details and append to `ainfo'.
863 866 */
864 867 curr = calloc(1, sizeof (ipadm_addr_info_t));
865 868 if (curr == NULL)
866 869 goto fail;
867 870 curr->ia_state = IFA_DISABLED;
868 871 if (last != NULL)
869 872 last->ia_ifa.ifa_next = &curr->ia_ifa;
870 873 else
871 874 ainfo = curr;
872 875 last = curr;
873 876 }
874 877 /*
875 878 * Fill relevant fields of `curr' from the persistent info
876 879 * in `nvladdr'. Call the appropriate function based on the
877 880 * `ia_state' value.
878 881 */
879 882 if (curr->ia_state == IFA_DISABLED)
880 883 status = i_ipadm_nvl2ainfo_persist(nvladdr, curr);
881 884 else
882 885 status = i_ipadm_nvl2ainfo_active(nvladdr, curr);
883 886 if (status != IPADM_SUCCESS)
884 887 goto fail;
885 888 }
886 889 *addrinfo = ainfo;
887 890 nvlist_free(onvl);
888 891 return (status);
889 892 fail:
890 893 /* On error, cleanup and return. */
891 894 nvlist_free(onvl);
892 895 ipadm_free_addr_info(ainfo);
893 896 *addrinfo = NULL;
894 897 return (status);
895 898 }
896 899
897 900 /*
898 901 * Callback function that sets the property `prefixlen' on the address
899 902 * object in `arg' to the value in `pval'.
900 903 */
901 904 /* ARGSUSED */
902 905 static ipadm_status_t
903 906 i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg,
904 907 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
905 908 {
906 909 struct sockaddr_storage netmask;
907 910 struct lifreq lifr;
908 911 int err, s;
909 912 unsigned long prefixlen, abits;
910 913 char *end;
911 914 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
912 915
913 916 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
914 917 return (IPADM_NOTSUP);
915 918
916 919 errno = 0;
917 920 prefixlen = strtoul(pval, &end, 10);
918 921 if (errno != 0 || *end != '\0')
919 922 return (IPADM_INVALID_ARG);
920 923
921 924 abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS);
922 925 if (prefixlen == 0 || prefixlen == (abits - 1))
923 926 return (IPADM_INVALID_ARG);
924 927
925 928 if ((err = plen2mask(prefixlen, af, (struct sockaddr *)&netmask)) != 0)
926 929 return (ipadm_errno2status(err));
927 930
928 931 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
929 932
930 933 bzero(&lifr, sizeof (lifr));
931 934 i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
932 935 sizeof (lifr.lifr_name));
933 936 (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
934 937 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
935 938 return (ipadm_errno2status(errno));
936 939
937 940 /* now, change the broadcast address to reflect the prefixlen */
938 941 if (af == AF_INET) {
939 942 /*
940 943 * get the interface address and set it, this should reset
941 944 * the broadcast address.
942 945 */
943 946 (void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr);
944 947 (void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
945 948 }
946 949
947 950 return (IPADM_SUCCESS);
948 951 }
949 952
950 953
951 954 /*
952 955 * Callback function that sets the given value `pval' to one of the
953 956 * properties among `deprecated', `private', and `transmit' as defined in
954 957 * `pdp', on the address object in `arg'.
955 958 */
956 959 /* ARGSUSED */
957 960 static ipadm_status_t
958 961 i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg,
959 962 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
960 963 {
961 964 char lifname[LIFNAMSIZ];
962 965 uint64_t on_flags = 0, off_flags = 0;
963 966 boolean_t on;
964 967 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
965 968
966 969 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
967 970 strcmp(pdp->ipd_name, "deprecated") == 0)
968 971 return (IPADM_NOTSUP);
969 972
970 973 if (strcmp(pval, IPADM_ONSTR) == 0)
971 974 on = B_TRUE;
972 975 else if (strcmp(pval, IPADM_OFFSTR) == 0)
973 976 on = B_FALSE;
974 977 else
975 978 return (IPADM_INVALID_ARG);
976 979
977 980 if (strcmp(pdp->ipd_name, "private") == 0) {
978 981 if (on)
979 982 on_flags = IFF_PRIVATE;
980 983 else
981 984 off_flags = IFF_PRIVATE;
982 985 } else if (strcmp(pdp->ipd_name, "transmit") == 0) {
983 986 if (on)
984 987 off_flags = IFF_NOXMIT;
985 988 else
986 989 on_flags = IFF_NOXMIT;
987 990 } else if (strcmp(pdp->ipd_name, "deprecated") == 0) {
988 991 if (on)
989 992 on_flags = IFF_DEPRECATED;
990 993 else
991 994 off_flags = IFF_DEPRECATED;
992 995 } else {
993 996 return (IPADM_PROP_UNKNOWN);
994 997 }
995 998
996 999 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
997 1000 return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags));
998 1001 }
999 1002
1000 1003 /*
1001 1004 * Callback function that sets the property `zone' on the address
1002 1005 * object in `arg' to the value in `pval'.
1003 1006 */
1004 1007 /* ARGSUSED */
1005 1008 static ipadm_status_t
1006 1009 i_ipadm_set_zone(ipadm_handle_t iph, const void *arg,
1007 1010 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1008 1011 {
1009 1012 struct lifreq lifr;
1010 1013 zoneid_t zoneid;
1011 1014 int s;
1012 1015
1013 1016 /*
1014 1017 * To modify the zone assignment such that it persists across
1015 1018 * reboots, zonecfg(1M) must be used.
1016 1019 */
1017 1020 if (flags & IPADM_OPT_PERSIST) {
1018 1021 return (IPADM_NOTSUP);
1019 1022 } else if (flags & IPADM_OPT_ACTIVE) {
1020 1023 /* put logical interface into all zones */
1021 1024 if (strcmp(pval, "all-zones") == 0) {
1022 1025 zoneid = ALL_ZONES;
1023 1026 } else {
1024 1027 /* zone must be ready or running */
1025 1028 if ((zoneid = getzoneidbyname(pval)) == -1)
1026 1029 return (ipadm_errno2status(errno));
1027 1030 }
1028 1031 } else {
1029 1032 return (IPADM_INVALID_ARG);
1030 1033 }
1031 1034
1032 1035 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1033 1036 bzero(&lifr, sizeof (lifr));
1034 1037 i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1035 1038 sizeof (lifr.lifr_name));
1036 1039 lifr.lifr_zoneid = zoneid;
1037 1040 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
1038 1041 return (ipadm_errno2status(errno));
1039 1042
1040 1043 return (IPADM_SUCCESS);
1041 1044 }
1042 1045
1043 1046 /*
1044 1047 * Callback function that gets the property `broadcast' for the address
1045 1048 * object in `arg'.
1046 1049 */
1047 1050 /* ARGSUSED */
1048 1051 static ipadm_status_t
1049 1052 i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
1050 1053 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1051 1054 uint_t valtype)
1052 1055 {
1053 1056 struct sockaddr_in *sin;
1054 1057 struct lifreq lifr;
1055 1058 char lifname[LIFNAMSIZ];
1056 1059 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1057 1060 ipadm_status_t status;
1058 1061 size_t nbytes = 0;
1059 1062 uint64_t ifflags = 0;
1060 1063
1061 1064 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1062 1065 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1063 1066 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1064 1067 if (status != IPADM_SUCCESS)
1065 1068 return (status);
1066 1069 if (!(ifflags & IFF_BROADCAST)) {
1067 1070 buf[0] = '\0';
1068 1071 return (IPADM_SUCCESS);
1069 1072 }
1070 1073 }
1071 1074
1072 1075 switch (valtype) {
1073 1076 case MOD_PROP_DEFAULT: {
1074 1077 struct sockaddr_storage mask;
1075 1078 struct in_addr broadaddr;
1076 1079 uint_t plen;
1077 1080 in_addr_t addr, maddr;
1078 1081 char val[MAXPROPVALLEN];
1079 1082 uint_t valsz = MAXPROPVALLEN;
1080 1083 ipadm_status_t status;
1081 1084 int err;
1082 1085 struct sockaddr_in *sin;
1083 1086
1084 1087 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) {
1085 1088 /*
1086 1089 * Since the address is unknown we cannot
1087 1090 * obtain default prefixlen
1088 1091 */
1089 1092 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP ||
1090 1093 ipaddr->ipadm_af == AF_INET6) {
1091 1094 buf[0] = '\0';
1092 1095 return (IPADM_SUCCESS);
1093 1096 }
1094 1097 /*
1095 1098 * For the static address, we get the address from the
1096 1099 * persistent db.
1097 1100 */
1098 1101 status = i_ipadm_get_static_addr_db(iph, ipaddr);
1099 1102 if (status != IPADM_SUCCESS)
1100 1103 return (status);
1101 1104 sin = SIN(&ipaddr->ipadm_static_addr);
1102 1105 addr = sin->sin_addr.s_addr;
1103 1106 } else {
1104 1107 /*
1105 1108 * If the address object is active, we retrieve the
1106 1109 * address from kernel.
1107 1110 */
1108 1111 bzero(&lifr, sizeof (lifr));
1109 1112 (void) strlcpy(lifr.lifr_name, lifname,
1110 1113 sizeof (lifr.lifr_name));
1111 1114 if (ioctl(iph->iph_sock, SIOCGLIFADDR,
1112 1115 (caddr_t)&lifr) < 0)
1113 1116 return (ipadm_errno2status(errno));
1114 1117
1115 1118 addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr;
1116 1119 }
1117 1120 /*
1118 1121 * For default broadcast address, get the address and the
1119 1122 * default prefixlen for that address and then compute the
1120 1123 * broadcast address.
1121 1124 */
1122 1125 status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af,
1123 1126 MOD_PROP_DEFAULT);
1124 1127 if (status != IPADM_SUCCESS)
1125 1128 return (status);
1126 1129
1127 1130 plen = atoi(val);
1128 1131 if ((err = plen2mask(plen, AF_INET,
1129 1132 (struct sockaddr *)&mask)) != 0)
1130 1133 return (ipadm_errno2status(err));
1131 1134 maddr = (SIN(&mask))->sin_addr.s_addr;
1132 1135 broadaddr.s_addr = (addr & maddr) | ~maddr;
1133 1136 nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr));
1134 1137 break;
1135 1138 }
1136 1139 case MOD_PROP_ACTIVE:
1137 1140 bzero(&lifr, sizeof (lifr));
1138 1141 (void) strlcpy(lifr.lifr_name, lifname,
1139 1142 sizeof (lifr.lifr_name));
1140 1143 if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR,
1141 1144 (caddr_t)&lifr) < 0) {
1142 1145 return (ipadm_errno2status(errno));
1143 1146 } else {
1144 1147 sin = SIN(&lifr.lifr_addr);
1145 1148 nbytes = snprintf(buf, *bufsize, "%s",
1146 1149 inet_ntoa(sin->sin_addr));
1147 1150 }
1148 1151 break;
1149 1152 default:
1150 1153 return (IPADM_INVALID_ARG);
1151 1154 }
1152 1155 if (nbytes >= *bufsize) {
1153 1156 /* insufficient buffer space */
1154 1157 *bufsize = nbytes + 1;
1155 1158 return (IPADM_NO_BUFS);
1156 1159 }
1157 1160 return (IPADM_SUCCESS);
1158 1161 }
1159 1162
1160 1163 /*
1161 1164 * Callback function that retrieves the value of the property `prefixlen'
1162 1165 * for the address object in `arg'.
1163 1166 */
1164 1167 /* ARGSUSED */
1165 1168 static ipadm_status_t
1166 1169 i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg,
1167 1170 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1168 1171 uint_t valtype)
1169 1172 {
1170 1173 struct lifreq lifr;
1171 1174 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1172 1175 char lifname[LIFNAMSIZ];
1173 1176 int s;
1174 1177 uint32_t prefixlen;
1175 1178 size_t nbytes;
1176 1179 ipadm_status_t status;
1177 1180 uint64_t lifflags;
1178 1181
1179 1182 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1180 1183 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1181 1184 status = i_ipadm_get_flags(iph, lifname, af, &lifflags);
1182 1185 if (status != IPADM_SUCCESS) {
1183 1186 return (status);
1184 1187 } else if (lifflags & IFF_POINTOPOINT) {
1185 1188 buf[0] = '\0';
1186 1189 return (status);
1187 1190 }
1188 1191 }
1189 1192
1190 1193 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1191 1194 bzero(&lifr, sizeof (lifr));
1192 1195 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
1193 1196 switch (valtype) {
1194 1197 case MOD_PROP_POSSIBLE:
1195 1198 if (af == AF_INET)
1196 1199 nbytes = snprintf(buf, *bufsize, "1-30,32");
1197 1200 else
1198 1201 nbytes = snprintf(buf, *bufsize, "1-126,128");
1199 1202 break;
1200 1203 case MOD_PROP_DEFAULT:
1201 1204 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1202 1205 /*
1203 1206 * For static addresses, we retrieve the address
1204 1207 * from kernel if it is active.
1205 1208 */
1206 1209 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
1207 1210 return (ipadm_errno2status(errno));
1208 1211 status = i_ipadm_get_default_prefixlen(
1209 1212 &lifr.lifr_addr, &prefixlen);
1210 1213 if (status != IPADM_SUCCESS)
1211 1214 return (status);
1212 1215 } else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) &&
1213 1216 ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
1214 1217 /*
1215 1218 * Since the address is unknown we cannot
1216 1219 * obtain default prefixlen
1217 1220 */
1218 1221 buf[0] = '\0';
1219 1222 return (IPADM_SUCCESS);
1220 1223 } else {
1221 1224 /*
1222 1225 * If not in active config, we use the address
1223 1226 * from persistent store.
1224 1227 */
1225 1228 status = i_ipadm_get_static_addr_db(iph, ipaddr);
1226 1229 if (status != IPADM_SUCCESS)
1227 1230 return (status);
1228 1231 status = i_ipadm_get_default_prefixlen(
1229 1232 &ipaddr->ipadm_static_addr, &prefixlen);
1230 1233 if (status != IPADM_SUCCESS)
1231 1234 return (status);
1232 1235 }
1233 1236 nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
1234 1237 break;
1235 1238 case MOD_PROP_ACTIVE:
1236 1239 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
1237 1240 return (ipadm_errno2status(errno));
1238 1241 prefixlen = lifr.lifr_addrlen;
1239 1242 nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
1240 1243 break;
1241 1244 default:
1242 1245 return (IPADM_INVALID_ARG);
1243 1246 }
1244 1247 if (nbytes >= *bufsize) {
1245 1248 /* insufficient buffer space */
1246 1249 *bufsize = nbytes + 1;
1247 1250 return (IPADM_NO_BUFS);
1248 1251 }
1249 1252 return (IPADM_SUCCESS);
1250 1253 }
1251 1254
1252 1255 /*
1253 1256 * Callback function that retrieves the value of one of the properties
1254 1257 * among `deprecated', `private', and `transmit' for the address object
1255 1258 * in `arg'.
1256 1259 */
1257 1260 /* ARGSUSED */
1258 1261 static ipadm_status_t
1259 1262 i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg,
1260 1263 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1261 1264 uint_t valtype)
1262 1265 {
1263 1266 boolean_t on = B_FALSE;
1264 1267 char lifname[LIFNAMSIZ];
1265 1268 ipadm_status_t status = IPADM_SUCCESS;
1266 1269 uint64_t ifflags;
1267 1270 size_t nbytes;
1268 1271 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1269 1272
1270 1273 switch (valtype) {
1271 1274 case MOD_PROP_DEFAULT:
1272 1275 if (strcmp(pdp->ipd_name, "private") == 0 ||
1273 1276 strcmp(pdp->ipd_name, "deprecated") == 0) {
1274 1277 on = B_FALSE;
1275 1278 } else if (strcmp(pdp->ipd_name, "transmit") == 0) {
1276 1279 on = B_TRUE;
1277 1280 } else {
1278 1281 return (IPADM_PROP_UNKNOWN);
1279 1282 }
1280 1283 break;
1281 1284 case MOD_PROP_ACTIVE:
1282 1285 /*
1283 1286 * If the address is present in active configuration, we
1284 1287 * retrieve it from kernel to get the property value.
1285 1288 * Else, there is no value to return.
1286 1289 */
1287 1290 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1288 1291 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1289 1292 if (status != IPADM_SUCCESS)
1290 1293 return (status);
1291 1294 if (strcmp(pdp->ipd_name, "private") == 0)
1292 1295 on = (ifflags & IFF_PRIVATE);
1293 1296 else if (strcmp(pdp->ipd_name, "transmit") == 0)
1294 1297 on = !(ifflags & IFF_NOXMIT);
1295 1298 else if (strcmp(pdp->ipd_name, "deprecated") == 0)
1296 1299 on = (ifflags & IFF_DEPRECATED);
1297 1300 break;
1298 1301 default:
1299 1302 return (IPADM_INVALID_ARG);
1300 1303 }
1301 1304 nbytes = snprintf(buf, *bufsize, "%s",
1302 1305 (on ? IPADM_ONSTR : IPADM_OFFSTR));
1303 1306 if (nbytes >= *bufsize) {
1304 1307 /* insufficient buffer space */
1305 1308 *bufsize = nbytes + 1;
1306 1309 status = IPADM_NO_BUFS;
1307 1310 }
1308 1311
1309 1312 return (status);
1310 1313 }
1311 1314
1312 1315 /*
1313 1316 * Callback function that retrieves the value of the property `zone'
1314 1317 * for the address object in `arg'.
1315 1318 */
1316 1319 /* ARGSUSED */
1317 1320 static ipadm_status_t
1318 1321 i_ipadm_get_zone(ipadm_handle_t iph, const void *arg,
1319 1322 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1320 1323 uint_t valtype)
1321 1324 {
1322 1325 struct lifreq lifr;
1323 1326 char zone_name[ZONENAME_MAX];
1324 1327 int s;
1325 1328 size_t nbytes = 0;
1326 1329
1327 1330 if (iph->iph_zoneid != GLOBAL_ZONEID) {
1328 1331 buf[0] = '\0';
1329 1332 return (IPADM_SUCCESS);
1330 1333 }
1331 1334
1332 1335 /*
1333 1336 * we are in global zone. See if the lifname is assigned to shared-ip
1334 1337 * zone or global zone.
1335 1338 */
1336 1339 switch (valtype) {
1337 1340 case MOD_PROP_DEFAULT:
1338 1341 if (getzonenamebyid(GLOBAL_ZONEID, zone_name,
1339 1342 sizeof (zone_name)) > 0)
1340 1343 nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1341 1344 else
1342 1345 return (ipadm_errno2status(errno));
1343 1346 break;
1344 1347 case MOD_PROP_ACTIVE:
1345 1348 bzero(&lifr, sizeof (lifr));
1346 1349 i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1347 1350 sizeof (lifr.lifr_name));
1348 1351 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1349 1352
1350 1353 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1)
1351 1354 return (ipadm_errno2status(errno));
1352 1355
1353 1356 if (lifr.lifr_zoneid == ALL_ZONES) {
1354 1357 nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
1355 1358 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
1356 1359 sizeof (zone_name)) < 0) {
1357 1360 return (ipadm_errno2status(errno));
1358 1361 } else {
1359 1362 nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1360 1363 }
1361 1364 break;
1362 1365 default:
1363 1366 return (IPADM_INVALID_ARG);
1364 1367 }
1365 1368 if (nbytes >= *bufsize) {
1366 1369 /* insufficient buffer space */
1367 1370 *bufsize = nbytes + 1;
1368 1371 return (IPADM_NO_BUFS);
1369 1372 }
1370 1373
1371 1374 return (IPADM_SUCCESS);
1372 1375 }
1373 1376
1374 1377 static ipadm_prop_desc_t *
1375 1378 i_ipadm_get_addrprop_desc(const char *pname)
1376 1379 {
1377 1380 int i;
1378 1381
1379 1382 for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1380 1383 if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1381 1384 (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1382 1385 strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
1383 1386 return (&ipadm_addrprop_table[i]);
1384 1387 }
1385 1388 return (NULL);
1386 1389 }
1387 1390
1388 1391 /*
1389 1392 * Gets the value of the given address property `pname' for the address
1390 1393 * object with name `aobjname'.
1391 1394 */
1392 1395 ipadm_status_t
1393 1396 ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,
1394 1397 uint_t *bufsize, const char *aobjname, uint_t valtype)
1395 1398 {
1396 1399 struct ipadm_addrobj_s ipaddr;
1397 1400 ipadm_status_t status = IPADM_SUCCESS;
1398 1401 sa_family_t af;
1399 1402 ipadm_prop_desc_t *pdp = NULL;
1400 1403
1401 1404 if (iph == NULL || pname == NULL || buf == NULL ||
1402 1405 bufsize == NULL || *bufsize == 0 || aobjname == NULL) {
1403 1406 return (IPADM_INVALID_ARG);
1404 1407 }
1405 1408
1406 1409 /* find the property in the property description table */
1407 1410 if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1408 1411 return (IPADM_PROP_UNKNOWN);
1409 1412
1410 1413 /*
1411 1414 * For the given aobjname, get the addrobj it represents and
1412 1415 * retrieve the property value for that object.
1413 1416 */
1414 1417 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1415 1418 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1416 1419 return (status);
1417 1420
1418 1421 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1419 1422 return (IPADM_NOTSUP);
1420 1423 af = ipaddr.ipadm_af;
1421 1424
1422 1425 /*
1423 1426 * Call the appropriate callback function to based on the field
1424 1427 * that was asked for.
1425 1428 */
1426 1429 switch (valtype) {
1427 1430 case IPADM_OPT_PERM:
1428 1431 status = i_ipadm_pd2permstr(pdp, buf, bufsize);
1429 1432 break;
1430 1433 case IPADM_OPT_ACTIVE:
1431 1434 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) {
1432 1435 buf[0] = '\0';
1433 1436 } else {
1434 1437 status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1435 1438 af, MOD_PROP_ACTIVE);
1436 1439 }
1437 1440 break;
1438 1441 case IPADM_OPT_DEFAULT:
1439 1442 status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1440 1443 af, MOD_PROP_DEFAULT);
1441 1444 break;
1442 1445 case IPADM_OPT_POSSIBLE:
1443 1446 if (pdp->ipd_get_range != NULL) {
1444 1447 status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf,
1445 1448 bufsize, af, MOD_PROP_POSSIBLE);
1446 1449 break;
1447 1450 }
1448 1451 buf[0] = '\0';
1449 1452 break;
1450 1453 case IPADM_OPT_PERSIST:
1451 1454 status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize,
1452 1455 &ipaddr);
1453 1456 break;
1454 1457 default:
1455 1458 status = IPADM_INVALID_ARG;
1456 1459 break;
1457 1460 }
1458 1461
1459 1462 return (status);
1460 1463 }
1461 1464
1462 1465 /*
1463 1466 * Sets the value of the given address property `pname' to `pval' for the
1464 1467 * address object with name `aobjname'.
1465 1468 */
1466 1469 ipadm_status_t
1467 1470 ipadm_set_addrprop(ipadm_handle_t iph, const char *pname,
1468 1471 const char *pval, const char *aobjname, uint_t pflags)
1469 1472 {
1470 1473 struct ipadm_addrobj_s ipaddr;
1471 1474 sa_family_t af;
1472 1475 ipadm_prop_desc_t *pdp = NULL;
1473 1476 char defbuf[MAXPROPVALLEN];
1474 1477 uint_t defbufsize = MAXPROPVALLEN;
1475 1478 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1476 1479 ipadm_status_t status = IPADM_SUCCESS;
1477 1480
1478 1481 /* Check for solaris.network.interface.config authorization */
1479 1482 if (!ipadm_check_auth())
1480 1483 return (IPADM_EAUTH);
1481 1484
1482 1485 if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 ||
1483 1486 pflags == IPADM_OPT_PERSIST ||
1484 1487 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) ||
1485 1488 (!reset && pval == NULL)) {
1486 1489 return (IPADM_INVALID_ARG);
1487 1490 }
1488 1491
1489 1492 /* find the property in the property description table */
1490 1493 if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1491 1494 return (IPADM_PROP_UNKNOWN);
1492 1495
1493 1496 if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL))
1494 1497 return (IPADM_NOTSUP);
1495 1498
1496 1499 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1497 1500 (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1498 1501 return (IPADM_INVALID_ARG);
1499 1502 }
1500 1503
1501 1504 /*
1502 1505 * For the given aobjname, get the addrobj it represents and
1503 1506 * set the property value for that object.
1504 1507 */
1505 1508 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
↓ open down ↓ |
1231 lines elided |
↑ open up ↑ |
1506 1509 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1507 1510 return (status);
1508 1511
1509 1512 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1510 1513 return (IPADM_OP_DISABLE_OBJ);
1511 1514
1512 1515 /* Persistent operation not allowed on a temporary object. */
1513 1516 if ((pflags & IPADM_OPT_PERSIST) &&
1514 1517 !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1515 1518 return (IPADM_TEMPORARY_OBJ);
1516 -
1517 1519 /*
1518 1520 * Currently, setting an address property on an address object of type
1519 1521 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1520 1522 * in.ndpd retrieving the address properties from ipmgmtd for given
1521 1523 * address object and then setting them on auto-configured addresses,
1522 1524 * whenever in.ndpd gets a new prefix. This will be supported in
1523 1525 * future releases.
1524 1526 */
1525 1527 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1526 1528 return (IPADM_NOTSUP);
1527 1529
1528 1530 /*
1529 1531 * Setting an address property on an address object that is
1530 1532 * not present in active configuration is not supported.
1531 1533 */
1532 1534 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1533 1535 return (IPADM_NOTSUP);
1534 1536
1535 1537 af = ipaddr.ipadm_af;
1536 1538 if (reset) {
1537 1539 /*
1538 1540 * If we were asked to reset the value, we need to fetch
1539 1541 * the default value and set the default value.
1540 1542 */
1541 1543 status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize,
1542 1544 af, MOD_PROP_DEFAULT);
1543 1545 if (status != IPADM_SUCCESS)
1544 1546 return (status);
1545 1547 pval = defbuf;
1546 1548 }
1547 1549 /* set the user provided or default property value */
1548 1550 status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags);
1549 1551 if (status != IPADM_SUCCESS)
1550 1552 return (status);
1551 1553
1552 1554 /*
1553 1555 * If IPADM_OPT_PERSIST was set in `flags', we need to store
1554 1556 * property and its value in persistent DB.
1555 1557 */
1556 1558 if (pflags & IPADM_OPT_PERSIST) {
1557 1559 status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr,
1558 1560 pflags);
1559 1561 }
1560 1562
1561 1563 return (status);
1562 1564 }
1563 1565
1564 1566 /*
1565 1567 * Remove the address specified by the address object in `addr'
1566 1568 * from kernel. If the address is on a non-zero logical interface, we do a
1567 1569 * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or
1568 1570 * :: for IPv6.
1569 1571 */
1570 1572 ipadm_status_t
1571 1573 i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr)
1572 1574 {
1573 1575 struct lifreq lifr;
1574 1576 int sock;
1575 1577 ipadm_status_t status;
1576 1578
1577 1579 bzero(&lifr, sizeof (lifr));
1578 1580 i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name));
1579 1581 sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1580 1582 if (addr->ipadm_lifnum == 0) {
1581 1583 /*
1582 1584 * Fake the deletion of the 0'th address by
1583 1585 * clearing IFF_UP and setting it to as 0.0.0.0 or ::.
1584 1586 */
1585 1587 status = i_ipadm_set_flags(iph, addr->ipadm_ifname,
1586 1588 addr->ipadm_af, 0, IFF_UP);
1587 1589 if (status != IPADM_SUCCESS)
1588 1590 return (status);
1589 1591 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
1590 1592 lifr.lifr_addr.ss_family = addr->ipadm_af;
1591 1593 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1592 1594 return (ipadm_errno2status(errno));
1593 1595 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
1594 1596 return (ipadm_errno2status(errno));
1595 1597 } else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
1596 1598 return (ipadm_errno2status(errno));
1597 1599 }
1598 1600
1599 1601 return (IPADM_SUCCESS);
1600 1602 }
1601 1603
1602 1604 /*
1603 1605 * Extracts the IPv6 address from the nvlist in `nvl'.
1604 1606 */
1605 1607 ipadm_status_t
1606 1608 i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr)
1607 1609 {
1608 1610 uint8_t *addr6;
1609 1611 uint_t n;
1610 1612
1611 1613 if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0)
1612 1614 return (IPADM_NOTFOUND);
1613 1615 assert(n == 16);
1614 1616 bcopy(addr6, in6_addr->s6_addr, n);
1615 1617 return (IPADM_SUCCESS);
1616 1618 }
1617 1619
1618 1620 /*
1619 1621 * Used to validate the given addrobj name string. Length of `aobjname'
1620 1622 * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an
1621 1623 * alphabetic character and it can only contain alphanumeric characters.
1622 1624 */
1623 1625 static boolean_t
1624 1626 i_ipadm_is_user_aobjname_valid(const char *aobjname)
1625 1627 {
1626 1628 const char *cp;
1627 1629
1628 1630 if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ ||
1629 1631 !isalpha(*aobjname)) {
1630 1632 return (B_FALSE);
1631 1633 }
1632 1634 for (cp = aobjname + 1; *cp && isalnum(*cp); cp++)
1633 1635 ;
1634 1636 return (*cp == '\0');
1635 1637 }
1636 1638
1637 1639 /*
1638 1640 * Computes the prefixlen for the given `addr' based on the netmask found using
1639 1641 * the order specified in /etc/nsswitch.conf. If not found, then the
1640 1642 * prefixlen is computed using the Classful subnetting semantics defined
1641 1643 * in RFC 791 for IPv4 and RFC 4291 for IPv6.
1642 1644 */
1643 1645 static ipadm_status_t
1644 1646 i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen)
1645 1647 {
1646 1648 sa_family_t af = addr->ss_family;
1647 1649 struct sockaddr_storage mask;
1648 1650 struct sockaddr_in *m = (struct sockaddr_in *)&mask;
1649 1651 struct sockaddr_in6 *sin6;
1650 1652 struct sockaddr_in *sin;
1651 1653 struct in_addr ia;
1652 1654 uint32_t prefixlen = 0;
1653 1655
1654 1656 switch (af) {
1655 1657 case AF_INET:
1656 1658 sin = SIN(addr);
1657 1659 ia.s_addr = ntohl(sin->sin_addr.s_addr);
1658 1660 get_netmask4(&ia, &m->sin_addr);
1659 1661 m->sin_addr.s_addr = htonl(m->sin_addr.s_addr);
1660 1662 m->sin_family = AF_INET;
1661 1663 prefixlen = mask2plen((struct sockaddr *)&mask);
1662 1664 break;
1663 1665 case AF_INET6:
1664 1666 sin6 = SIN6(addr);
1665 1667 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
1666 1668 prefixlen = 10;
1667 1669 else
1668 1670 prefixlen = 64;
1669 1671 break;
1670 1672 default:
1671 1673 return (IPADM_INVALID_ARG);
1672 1674 }
1673 1675 *plen = prefixlen;
1674 1676 return (IPADM_SUCCESS);
1675 1677 }
1676 1678
1677 1679 ipadm_status_t
1678 1680 i_ipadm_resolve_addr(const char *name, sa_family_t af,
1679 1681 struct sockaddr_storage *ss)
1680 1682 {
1681 1683 struct addrinfo hints, *ai;
1682 1684 int rc;
1683 1685 struct sockaddr_in6 *sin6;
1684 1686 struct sockaddr_in *sin;
1685 1687 boolean_t is_mapped;
1686 1688
1687 1689 (void) memset(&hints, 0, sizeof (hints));
1688 1690 hints.ai_family = af;
1689 1691 hints.ai_flags = (AI_ALL | AI_V4MAPPED);
1690 1692 rc = getaddrinfo(name, NULL, &hints, &ai);
1691 1693 if (rc != 0) {
1692 1694 if (rc == EAI_NONAME)
1693 1695 return (IPADM_BAD_ADDR);
1694 1696 else
1695 1697 return (IPADM_FAILURE);
1696 1698 }
1697 1699 if (ai->ai_next != NULL) {
1698 1700 /* maps to more than one hostname */
1699 1701 freeaddrinfo(ai);
1700 1702 return (IPADM_BAD_HOSTNAME);
1701 1703 }
1702 1704 /* LINTED E_BAD_PTR_CAST_ALIGN */
1703 1705 is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr);
1704 1706 if (is_mapped) {
1705 1707 sin = SIN(ss);
1706 1708 sin->sin_family = AF_INET;
1707 1709 /* LINTED E_BAD_PTR_CAST_ALIGN */
1708 1710 IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr,
1709 1711 &sin->sin_addr);
1710 1712 } else {
1711 1713 sin6 = SIN6(ss);
1712 1714 sin6->sin6_family = AF_INET6;
1713 1715 bcopy(ai->ai_addr, sin6, sizeof (*sin6));
1714 1716 }
1715 1717 freeaddrinfo(ai);
1716 1718 return (IPADM_SUCCESS);
1717 1719 }
1718 1720
1719 1721 /*
1720 1722 * This takes a static address string <addr>[/<mask>] or a hostname
1721 1723 * and maps it to a single numeric IP address, consulting DNS if
1722 1724 * hostname was provided. If a specific address family was requested,
1723 1725 * an error is returned if the given hostname does not map to an address
1724 1726 * of the given family. Note that this function returns failure
1725 1727 * if the name maps to more than one IP address.
1726 1728 */
1727 1729 ipadm_status_t
1728 1730 ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af)
1729 1731 {
1730 1732 char *prefixlenstr;
1731 1733 uint32_t prefixlen = 0;
1732 1734 char *endp;
1733 1735 /*
1734 1736 * We use (NI_MAXHOST + 5) because the longest possible
1735 1737 * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4
1736 1738 * or a maximum of 128 for IPv6 + '\0') chars
1737 1739 */
1738 1740 char addrstr[NI_MAXHOST + 5];
1739 1741 ipadm_status_t status;
1740 1742
1741 1743 (void) snprintf(addrstr, sizeof (addrstr), "%s", astr);
1742 1744 if ((prefixlenstr = strchr(addrstr, '/')) != NULL) {
1743 1745 *prefixlenstr++ = '\0';
1744 1746 errno = 0;
1745 1747 prefixlen = strtoul(prefixlenstr, &endp, 10);
1746 1748 if (errno != 0 || *endp != '\0')
1747 1749 return (IPADM_INVALID_ARG);
1748 1750 if ((af == AF_INET && prefixlen > IP_ABITS) ||
1749 1751 (af == AF_INET6 && prefixlen > IPV6_ABITS))
1750 1752 return (IPADM_INVALID_ARG);
1751 1753 }
1752 1754
1753 1755 status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr);
1754 1756 if (status == IPADM_SUCCESS) {
1755 1757 (void) strlcpy(ipaddr->ipadm_static_aname, addrstr,
1756 1758 sizeof (ipaddr->ipadm_static_aname));
1757 1759 ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family;
1758 1760 ipaddr->ipadm_static_prefixlen = prefixlen;
1759 1761 }
1760 1762 return (status);
1761 1763 }
1762 1764
1763 1765 /*
1764 1766 * Gets the static source address from the address object in `ipaddr'.
1765 1767 * Memory for `addr' should be already allocated by the caller.
1766 1768 */
1767 1769 ipadm_status_t
1768 1770 ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1769 1771 {
1770 1772 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1771 1773 addr == NULL) {
1772 1774 return (IPADM_INVALID_ARG);
1773 1775 }
1774 1776 *addr = ipaddr->ipadm_static_addr;
1775 1777
1776 1778 return (IPADM_SUCCESS);
1777 1779 }
1778 1780 /*
1779 1781 * Set up tunnel destination address in ipaddr by contacting DNS.
1780 1782 * The function works similar to ipadm_set_addr().
1781 1783 * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
1782 1784 * if dst_addr resolves to more than one address. The caller has to verify
1783 1785 * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
1784 1786 */
1785 1787 ipadm_status_t
1786 1788 ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
1787 1789 {
1788 1790 ipadm_status_t status;
1789 1791
1790 1792 /* mask lengths are not meaningful for point-to-point interfaces. */
1791 1793 if (strchr(daddrstr, '/') != NULL)
1792 1794 return (IPADM_BAD_ADDR);
1793 1795
1794 1796 status = i_ipadm_resolve_addr(daddrstr, af,
1795 1797 &ipaddr->ipadm_static_dst_addr);
1796 1798 if (status == IPADM_SUCCESS) {
1797 1799 (void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,
1798 1800 sizeof (ipaddr->ipadm_static_dname));
1799 1801 }
1800 1802 return (status);
1801 1803 }
1802 1804
1803 1805 /*
1804 1806 * Sets the interface ID in the address object `ipaddr' with the address
1805 1807 * in the string `interface_id'. This interface ID will be used when
1806 1808 * ipadm_create_addr() is called with `ipaddr' with address type
1807 1809 * set to IPADM_ADDR_IPV6_ADDRCONF.
1808 1810 */
1809 1811 ipadm_status_t
1810 1812 ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id)
1811 1813 {
1812 1814 struct sockaddr_in6 *sin6;
1813 1815 char *end;
1814 1816 char *cp;
1815 1817 uint32_t prefixlen;
1816 1818 char addrstr[INET6_ADDRSTRLEN + 1];
1817 1819
1818 1820 if (ipaddr == NULL || interface_id == NULL ||
1819 1821 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
1820 1822 return (IPADM_INVALID_ARG);
1821 1823
1822 1824 (void) strlcpy(addrstr, interface_id, sizeof (addrstr));
1823 1825 if ((cp = strchr(addrstr, '/')) == NULL)
1824 1826 return (IPADM_INVALID_ARG);
1825 1827 *cp++ = '\0';
1826 1828 sin6 = &ipaddr->ipadm_intfid;
1827 1829 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) {
1828 1830 errno = 0;
1829 1831 prefixlen = strtoul(cp, &end, 10);
1830 1832 if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS)
1831 1833 return (IPADM_INVALID_ARG);
1832 1834 sin6->sin6_family = AF_INET6;
1833 1835 ipaddr->ipadm_intfidlen = prefixlen;
1834 1836 return (IPADM_SUCCESS);
1835 1837 }
1836 1838 return (IPADM_INVALID_ARG);
1837 1839 }
1838 1840
1839 1841 /*
1840 1842 * Sets the value for the field `ipadm_stateless' in address object `ipaddr'.
1841 1843 */
1842 1844 ipadm_status_t
1843 1845 ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless)
1844 1846 {
1845 1847 if (ipaddr == NULL ||
1846 1848 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
1847 1849 return (IPADM_INVALID_ARG);
1848 1850 ipaddr->ipadm_stateless = stateless;
1849 1851
1850 1852 return (IPADM_SUCCESS);
1851 1853 }
1852 1854
1853 1855 /*
1854 1856 * Sets the value for the field `ipadm_stateful' in address object `ipaddr'.
1855 1857 */
1856 1858 ipadm_status_t
1857 1859 ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful)
1858 1860 {
1859 1861 if (ipaddr == NULL ||
1860 1862 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
1861 1863 return (IPADM_INVALID_ARG);
1862 1864 ipaddr->ipadm_stateful = stateful;
1863 1865
1864 1866 return (IPADM_SUCCESS);
1865 1867 }
1866 1868
1867 1869 /*
1868 1870 * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'.
1869 1871 * The field is used during the address creation with address
1870 1872 * type IPADM_ADDR_DHCP. It specifies if the interface should be set
1871 1873 * as a primary interface for getting dhcp global options from the DHCP server.
1872 1874 */
1873 1875 ipadm_status_t
1874 1876 ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary)
1875 1877 {
1876 1878 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1877 1879 return (IPADM_INVALID_ARG);
1878 1880 ipaddr->ipadm_primary = primary;
1879 1881
1880 1882 return (IPADM_SUCCESS);
1881 1883 }
1882 1884
1883 1885 /*
1884 1886 * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
1885 1887 * This field is used during the address creation with address type
1886 1888 * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
1887 1889 * should wait before returning while the dhcp address is being acquired
1888 1890 * by the dhcpagent.
1889 1891 * Possible values:
1890 1892 * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
1891 1893 * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
1892 1894 * - <integer> : Wait the specified number of seconds before returning.
1893 1895 */
1894 1896 ipadm_status_t
1895 1897 ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
1896 1898 {
1897 1899 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1898 1900 return (IPADM_INVALID_ARG);
1899 1901 ipaddr->ipadm_wait = wait;
1900 1902 return (IPADM_SUCCESS);
1901 1903 }
1902 1904
1903 1905 /*
1904 1906 * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
1905 1907 * If the `aobjname' already exists in the daemon's `aobjmap' then
1906 1908 * IPADM_ADDROBJ_EXISTS will be returned.
1907 1909 *
1908 1910 * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
1909 1911 * daemon will generate an `aobjname' for the given `ipaddr'.
1910 1912 */
1911 1913 ipadm_status_t
1912 1914 i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
1913 1915 {
1914 1916 ipmgmt_aobjop_arg_t larg;
1915 1917 ipmgmt_aobjop_rval_t rval, *rvalp;
1916 1918 int err;
1917 1919
1918 1920 bzero(&larg, sizeof (larg));
1919 1921 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
1920 1922 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
1921 1923 sizeof (larg.ia_aobjname));
1922 1924 (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
1923 1925 sizeof (larg.ia_ifname));
1924 1926 larg.ia_family = ipaddr->ipadm_af;
1925 1927 larg.ia_atype = ipaddr->ipadm_atype;
1926 1928
1927 1929 rvalp = &rval;
1928 1930 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
1929 1931 sizeof (rval), B_FALSE);
1930 1932 if (err == 0 && ipaddr->ipadm_aobjname[0] == '\0') {
1931 1933 /* copy the daemon generated `aobjname' into `ipadddr' */
1932 1934 (void) strlcpy(ipaddr->ipadm_aobjname, rval.ir_aobjname,
1933 1935 sizeof (ipaddr->ipadm_aobjname));
1934 1936 }
1935 1937 if (err == EEXIST)
1936 1938 return (IPADM_ADDROBJ_EXISTS);
1937 1939 return (ipadm_errno2status(err));
1938 1940 }
1939 1941
1940 1942 /*
1941 1943 * Sets the logical interface number in the ipmgmtd's memory map for the
1942 1944 * address object `ipaddr'. If another address object has the same
1943 1945 * logical interface number, IPADM_ADDROBJ_EXISTS is returned.
1944 1946 */
1945 1947 ipadm_status_t
1946 1948 i_ipadm_setlifnum_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
1947 1949 {
1948 1950 ipmgmt_aobjop_arg_t larg;
1949 1951 ipmgmt_retval_t rval, *rvalp;
1950 1952 int err;
1951 1953
1952 1954 if (iph->iph_flags & IPH_IPMGMTD)
1953 1955 return (IPADM_SUCCESS);
1954 1956
1955 1957 bzero(&larg, sizeof (larg));
1956 1958 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM;
1957 1959 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
1958 1960 sizeof (larg.ia_aobjname));
1959 1961 larg.ia_lnum = ipaddr->ipadm_lifnum;
1960 1962 (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
1961 1963 sizeof (larg.ia_ifname));
1962 1964 larg.ia_family = ipaddr->ipadm_af;
1963 1965
1964 1966 rvalp = &rval;
1965 1967 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
1966 1968 sizeof (rval), B_FALSE);
1967 1969 if (err == EEXIST)
1968 1970 return (IPADM_ADDROBJ_EXISTS);
1969 1971 return (ipadm_errno2status(err));
1970 1972 }
1971 1973
1972 1974 /*
1973 1975 * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface
1974 1976 * `ifname'. If a hostname is present, it is resolved before the address
1975 1977 * is created.
1976 1978 */
1977 1979 ipadm_status_t
1978 1980 i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl,
1979 1981 sa_family_t af)
1980 1982 {
1981 1983 char *prefixlenstr = NULL;
1982 1984 char *upstr = NULL;
1983 1985 char *sname = NULL, *dname = NULL;
1984 1986 struct ipadm_addrobj_s ipaddr;
1985 1987 char *aobjname = NULL;
1986 1988 nvlist_t *nvaddr = NULL;
1987 1989 nvpair_t *nvp;
1988 1990 char *cidraddr;
1989 1991 char *name;
1990 1992 ipadm_status_t status;
1991 1993 int err = 0;
1992 1994 uint32_t flags = IPADM_OPT_ACTIVE;
1993 1995
1994 1996 /* retrieve the address information */
1995 1997 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
1996 1998 nvp = nvlist_next_nvpair(nvl, nvp)) {
1997 1999 name = nvpair_name(nvp);
1998 2000 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 ||
1999 2001 strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
2000 2002 err = nvpair_value_nvlist(nvp, &nvaddr);
2001 2003 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
2002 2004 err = nvpair_value_string(nvp, &aobjname);
2003 2005 } else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) {
2004 2006 err = nvpair_value_string(nvp, &prefixlenstr);
2005 2007 } else if (strcmp(name, "up") == 0) {
2006 2008 err = nvpair_value_string(nvp, &upstr);
2007 2009 }
2008 2010 if (err != 0)
2009 2011 return (ipadm_errno2status(err));
2010 2012 }
2011 2013 for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2012 2014 nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2013 2015 name = nvpair_name(nvp);
2014 2016 if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0)
2015 2017 err = nvpair_value_string(nvp, &sname);
2016 2018 else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
2017 2019 err = nvpair_value_string(nvp, &dname);
2018 2020 if (err != 0)
2019 2021 return (ipadm_errno2status(err));
2020 2022 }
2021 2023
2022 2024 if (strcmp(upstr, "yes") == 0)
2023 2025 flags |= IPADM_OPT_UP;
2024 2026
↓ open down ↓ |
498 lines elided |
↑ open up ↑ |
2025 2027 /* build the address object from the above information */
2026 2028 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
2027 2029 if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
2028 2030 if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
2029 2031 return (IPADM_NO_MEMORY);
2030 2032 status = ipadm_set_addr(&ipaddr, cidraddr, af);
2031 2033 free(cidraddr);
2032 2034 } else {
2033 2035 status = ipadm_set_addr(&ipaddr, sname, af);
2034 2036 }
2035 - if (status != IPADM_SUCCESS)
2036 - return (status);
2037 +// if (status != IPADM_SUCCESS)
2038 +// return (status);
2037 2039
2038 2040 if (dname != NULL) {
2039 2041 status = ipadm_set_dst_addr(&ipaddr, dname, af);
2040 2042 if (status != IPADM_SUCCESS)
2041 2043 return (status);
2042 2044 }
2043 2045 return (i_ipadm_create_addr(iph, &ipaddr, flags));
2044 2046 }
2045 2047
2046 2048 /*
2047 2049 * Creates a dhcp address on the interface `ifname' based on the
2048 2050 * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2049 2051 */
2050 2052 ipadm_status_t
2051 2053 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2052 2054 {
2053 2055 int32_t wait;
2054 2056 boolean_t primary;
2055 2057 nvlist_t *nvdhcp;
2056 2058 nvpair_t *nvp;
2057 2059 char *name;
2058 2060 struct ipadm_addrobj_s ipaddr;
2059 2061 char *aobjname;
2060 2062 int err = 0;
2061 2063
2062 2064 /* Extract the dhcp parameters */
2063 2065 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2064 2066 nvp = nvlist_next_nvpair(nvl, nvp)) {
2065 2067 name = nvpair_name(nvp);
2066 2068 if (strcmp(name, IPADM_NVP_DHCP) == 0)
2067 2069 err = nvpair_value_nvlist(nvp, &nvdhcp);
2068 2070 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2069 2071 err = nvpair_value_string(nvp, &aobjname);
2070 2072 if (err != 0)
2071 2073 return (ipadm_errno2status(err));
2072 2074 }
2073 2075 for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
2074 2076 nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
2075 2077 name = nvpair_name(nvp);
2076 2078 if (strcmp(name, IPADM_NVP_WAIT) == 0)
2077 2079 err = nvpair_value_int32(nvp, &wait);
2078 2080 else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
2079 2081 err = nvpair_value_boolean_value(nvp, &primary);
2080 2082 if (err != 0)
2081 2083 return (ipadm_errno2status(err));
2082 2084 }
2083 2085
2084 2086 /* Build the address object */
2085 2087 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
2086 2088 ipaddr.ipadm_primary = primary;
2087 2089 if (iph->iph_flags & IPH_INIT)
2088 2090 ipaddr.ipadm_wait = 0;
2089 2091 else
2090 2092 ipaddr.ipadm_wait = wait;
2091 2093 ipaddr.ipadm_af = AF_INET;
2092 2094 return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
2093 2095 }
2094 2096
2095 2097 /*
2096 2098 * Creates auto-configured addresses on the interface `ifname' based on
2097 2099 * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
2098 2100 */
2099 2101 ipadm_status_t
2100 2102 i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2101 2103 {
2102 2104 struct ipadm_addrobj_s ipaddr;
2103 2105 char *stateful = NULL, *stateless = NULL;
2104 2106 uint_t n;
2105 2107 uint8_t *addr6 = NULL;
2106 2108 uint32_t intfidlen = 0;
2107 2109 char *aobjname;
2108 2110 nvlist_t *nvaddr;
2109 2111 nvpair_t *nvp;
2110 2112 char *name;
2111 2113 int err = 0;
2112 2114
2113 2115 /* Extract the parameters */
2114 2116 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2115 2117 nvp = nvlist_next_nvpair(nvl, nvp)) {
2116 2118 name = nvpair_name(nvp);
2117 2119 if (strcmp(name, IPADM_NVP_INTFID) == 0)
2118 2120 err = nvpair_value_nvlist(nvp, &nvaddr);
2119 2121 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2120 2122 err = nvpair_value_string(nvp, &aobjname);
2121 2123 if (err != 0)
2122 2124 return (ipadm_errno2status(err));
2123 2125 }
2124 2126 for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2125 2127 nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2126 2128 name = nvpair_name(nvp);
2127 2129 if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0)
2128 2130 err = nvpair_value_uint8_array(nvp, &addr6, &n);
2129 2131 if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0)
2130 2132 err = nvpair_value_uint32(nvp, &intfidlen);
2131 2133 else if (strcmp(name, IPADM_NVP_STATELESS) == 0)
2132 2134 err = nvpair_value_string(nvp, &stateless);
2133 2135 else if (strcmp(name, IPADM_NVP_STATEFUL) == 0)
2134 2136 err = nvpair_value_string(nvp, &stateful);
2135 2137 if (err != 0)
2136 2138 return (ipadm_errno2status(err));
2137 2139 }
2138 2140 /* Build the address object. */
2139 2141 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF);
2140 2142 if (intfidlen > 0) {
2141 2143 ipaddr.ipadm_intfidlen = intfidlen;
2142 2144 bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n);
2143 2145 }
2144 2146 ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
2145 2147 ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
2146 2148 return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE));
2147 2149 }
2148 2150
2149 2151 /*
2150 2152 * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on
2151 2153 * the provided `type'. `aobjname' represents the address object name, which
2152 2154 * is of the form `<ifname>/<addressname>'.
2153 2155 *
2154 2156 * The caller has to minimally provide <ifname>. If <addressname> is not
2155 2157 * provided, then a default one will be generated by the API.
2156 2158 */
2157 2159 ipadm_status_t
2158 2160 ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname,
2159 2161 ipadm_addrobj_t *ipaddr)
2160 2162 {
2161 2163 ipadm_addrobj_t newaddr;
2162 2164 ipadm_status_t status;
2163 2165 char *aname, *cp;
2164 2166 char ifname[IPADM_AOBJSIZ];
2165 2167 ifspec_t ifsp;
2166 2168
2167 2169 if (ipaddr == NULL)
2168 2170 return (IPADM_INVALID_ARG);
2169 2171 *ipaddr = NULL;
2170 2172
↓ open down ↓ |
124 lines elided |
↑ open up ↑ |
2171 2173 if (aobjname == NULL || aobjname[0] == '\0')
2172 2174 return (IPADM_INVALID_ARG);
2173 2175
2174 2176 if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2175 2177 return (IPADM_INVALID_ARG);
2176 2178
2177 2179 if ((aname = strchr(ifname, '/')) != NULL)
2178 2180 *aname++ = '\0';
2179 2181
2180 2182 /* Check if the interface name is valid. */
2181 - if (!ifparse_ifspec(ifname, &ifsp))
2183 + if (!ifparse_ifspec(ifname, &ifsp)) {
2182 2184 return (IPADM_INVALID_ARG);
2183 -
2185 + }
2184 2186 /* Check if the given addrobj name is valid. */
2185 - if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2187 + if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname)) {
2186 2188 return (IPADM_INVALID_ARG);
2187 -
2189 + }
2188 2190 if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2189 2191 return (IPADM_NO_MEMORY);
2190 2192
2191 2193 /*
2192 2194 * If the ifname has logical interface number, extract it and assign
2193 2195 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2194 2196 * this today. We will check for the validity later in
2195 2197 * i_ipadm_validate_create_addr().
2196 2198 */
2197 2199 if (ifsp.ifsp_lunvalid) {
2198 2200 newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2199 2201 cp = strchr(ifname, IPADM_LOGICAL_SEP);
2200 2202 *cp = '\0';
2201 2203 }
2202 2204 (void) strlcpy(newaddr->ipadm_ifname, ifname,
2203 2205 sizeof (newaddr->ipadm_ifname));
2204 2206
2205 2207 if (aname != NULL) {
2206 2208 (void) snprintf(newaddr->ipadm_aobjname,
2207 2209 sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
2208 2210 }
2209 2211
2210 2212 switch (type) {
2211 2213 case IPADM_ADDR_IPV6_ADDRCONF:
2212 2214 newaddr->ipadm_intfidlen = 0;
2213 2215 newaddr->ipadm_stateful = B_TRUE;
2214 2216 newaddr->ipadm_stateless = B_TRUE;
2215 2217 newaddr->ipadm_af = AF_INET6;
2216 2218 break;
2217 2219
2218 2220 case IPADM_ADDR_DHCP:
2219 2221 newaddr->ipadm_primary = B_FALSE;
2220 2222 newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
2221 2223 newaddr->ipadm_af = AF_INET;
2222 2224 break;
2223 2225
2224 2226 case IPADM_ADDR_STATIC:
2225 2227 newaddr->ipadm_af = AF_UNSPEC;
2226 2228 newaddr->ipadm_static_prefixlen = 0;
2227 2229 break;
2228 2230
2229 2231 default:
2230 2232 status = IPADM_INVALID_ARG;
2231 2233 goto fail;
2232 2234 }
2233 2235 newaddr->ipadm_atype = type;
2234 2236 *ipaddr = newaddr;
2235 2237 return (IPADM_SUCCESS);
2236 2238 fail:
2237 2239 free(newaddr);
2238 2240 return (status);
2239 2241 }
2240 2242
2241 2243 /*
2242 2244 * Returns `aobjname' from the address object in `ipaddr'.
2243 2245 */
2244 2246 ipadm_status_t
2245 2247 ipadm_get_aobjname(const ipadm_addrobj_t ipaddr, char *aobjname, size_t len)
2246 2248 {
2247 2249 if (ipaddr == NULL || aobjname == NULL)
2248 2250 return (IPADM_INVALID_ARG);
2249 2251 if (strlcpy(aobjname, ipaddr->ipadm_aobjname, len) >= len)
2250 2252 return (IPADM_INVALID_ARG);
2251 2253
2252 2254 return (IPADM_SUCCESS);
2253 2255 }
2254 2256
2255 2257 /*
2256 2258 * Frees the address object in `ipaddr'.
2257 2259 */
2258 2260 void
2259 2261 ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)
2260 2262 {
2261 2263 free(ipaddr);
2262 2264 }
2263 2265
2264 2266 /*
2265 2267 * Retrieves the logical interface name from `ipaddr' and stores the
2266 2268 * string in `lifname'.
2267 2269 */
2268 2270 void
2269 2271 i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize)
2270 2272 {
2271 2273 if (ipaddr->ipadm_lifnum != 0) {
2272 2274 (void) snprintf(lifname, lifnamesize, "%s:%d",
2273 2275 ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum);
2274 2276 } else {
2275 2277 (void) snprintf(lifname, lifnamesize, "%s",
2276 2278 ipaddr->ipadm_ifname);
2277 2279 }
2278 2280 }
2279 2281
2280 2282 /*
2281 2283 * Checks if a non-zero static address is present on the 0th logical interface
2282 2284 * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it
2283 2285 * also checks if the interface is under DHCP control. If the condition is true,
2284 2286 * the output argument `exists' will be set to B_TRUE. Otherwise, `exists'
2285 2287 * is set to B_FALSE.
2286 2288 *
2287 2289 * Note that *exists will not be initialized if an error is encountered.
2288 2290 */
2289 2291 static ipadm_status_t
2290 2292 i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname,
2291 2293 sa_family_t af, boolean_t *exists)
2292 2294 {
2293 2295 struct lifreq lifr;
2294 2296 int sock;
2295 2297
2296 2298 /* For IPH_LEGACY, a new logical interface will never be added. */
2297 2299 if (iph->iph_flags & IPH_LEGACY) {
2298 2300 *exists = B_FALSE;
2299 2301 return (IPADM_SUCCESS);
2300 2302 }
2301 2303 bzero(&lifr, sizeof (lifr));
2302 2304 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2303 2305 if (af == AF_INET) {
2304 2306 sock = iph->iph_sock;
2305 2307 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
2306 2308 return (ipadm_errno2status(errno));
2307 2309 if (lifr.lifr_flags & IFF_DHCPRUNNING) {
2308 2310 *exists = B_TRUE;
2309 2311 return (IPADM_SUCCESS);
2310 2312 }
2311 2313 } else {
2312 2314 sock = iph->iph_sock6;
2313 2315 }
2314 2316 if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
2315 2317 return (ipadm_errno2status(errno));
2316 2318 *exists = !sockaddrunspec((struct sockaddr *)&lifr.lifr_addr);
2317 2319
2318 2320 return (IPADM_SUCCESS);
2319 2321 }
2320 2322
2321 2323 /*
2322 2324 * Adds a new logical interface in the kernel for interface
2323 2325 * `addr->ipadm_ifname', if there is a non-zero address on the 0th
2324 2326 * logical interface or if the 0th logical interface is under DHCP
2325 2327 * control. On success, it sets the lifnum in the address object `addr'.
2326 2328 */
2327 2329 ipadm_status_t
2328 2330 i_ipadm_do_addif(ipadm_handle_t iph, ipadm_addrobj_t addr)
2329 2331 {
2330 2332 ipadm_status_t status;
2331 2333 boolean_t addif;
2332 2334 struct lifreq lifr;
2333 2335 int sock;
2334 2336
2335 2337 addr->ipadm_lifnum = 0;
2336 2338 status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname,
2337 2339 addr->ipadm_af, &addif);
2338 2340 if (status != IPADM_SUCCESS)
2339 2341 return (status);
2340 2342 if (addif) {
2341 2343 /*
2342 2344 * If there is an address on 0th logical interface,
2343 2345 * add a new logical interface.
2344 2346 */
2345 2347 bzero(&lifr, sizeof (lifr));
2346 2348 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2347 2349 sizeof (lifr.lifr_name));
2348 2350 sock = (addr->ipadm_af == AF_INET ? iph->iph_sock :
2349 2351 iph->iph_sock6);
2350 2352 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2351 2353 return (ipadm_errno2status(errno));
2352 2354 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2353 2355 }
2354 2356 return (IPADM_SUCCESS);
2355 2357 }
2356 2358
2357 2359 /*
2358 2360 * Reads all the address lines from the persistent DB into the nvlist `onvl',
↓ open down ↓ |
161 lines elided |
↑ open up ↑ |
2359 2361 * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2360 2362 * it returns all the addresses for the given interface `ifname'.
2361 2363 * If an `aobjname' is specified, then the address line corresponding to
2362 2364 * that name will be returned.
2363 2365 */
2364 2366 static ipadm_status_t
2365 2367 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2366 2368 const char *aobjname, nvlist_t **onvl)
2367 2369 {
2368 2370 ipmgmt_getaddr_arg_t garg;
2369 - ipmgmt_get_rval_t *rvalp;
2370 - int err;
2371 - size_t nvlsize;
2372 - char *nvlbuf;
2373 2371
2374 2372 /* Populate the door_call argument structure */
2375 2373 bzero(&garg, sizeof (garg));
2376 2374 garg.ia_cmd = IPMGMT_CMD_GETADDR;
2377 2375 if (aobjname != NULL)
2378 2376 (void) strlcpy(garg.ia_aobjname, aobjname,
2379 2377 sizeof (garg.ia_aobjname));
2380 2378 if (ifname != NULL)
2381 2379 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2382 2380
2383 - rvalp = malloc(sizeof (ipmgmt_get_rval_t));
2384 - err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp,
2385 - sizeof (*rvalp), B_TRUE);
2386 - if (err == 0) {
2387 - nvlsize = rvalp->ir_nvlsize;
2388 - nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
2389 - err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
2390 - }
2391 - free(rvalp);
2392 - return (ipadm_errno2status(err));
2381 + return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
2393 2382 }
2394 2383
2395 2384 /*
2396 2385 * Adds the IP address contained in the 'ipaddr' argument to the physical
2397 2386 * interface represented by 'ifname' after doing the required validation.
2398 2387 * If the interface does not exist, it is created before the address is
2399 2388 * added.
2400 2389 *
2401 2390 * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2402 2391 * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2403 2392 * if provided, will be ignored and replaced with the newly generated name.
2404 2393 * The interface name provided has to be a logical interface name that
2405 2394 * already exists. No new logical interface will be added in this function.
2406 2395 *
2407 2396 * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2408 2397 * are plumbed (if they haven't been already). Otherwise, just the interface
2409 2398 * specified in `addr' is plumbed.
2410 2399 */
2411 2400 ipadm_status_t
2412 2401 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2413 2402 {
2414 2403 ipadm_status_t status;
2415 2404 sa_family_t af;
2416 2405 sa_family_t daf;
2417 2406 sa_family_t other_af;
2418 2407 boolean_t created_af = B_FALSE;
2419 2408 boolean_t created_other_af = B_FALSE;
2420 2409 ipadm_addr_type_t type;
2421 2410 char *ifname = addr->ipadm_ifname;
2422 2411 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2423 2412 boolean_t aobjfound;
2424 2413 boolean_t is_6to4;
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
2425 2414 struct lifreq lifr;
2426 2415 uint64_t ifflags;
2427 2416 boolean_t is_boot = (iph->iph_flags & IPH_IPMGMTD);
2428 2417
2429 2418 /* check for solaris.network.interface.config authorization */
2430 2419 if (!ipadm_check_auth())
2431 2420 return (IPADM_EAUTH);
2432 2421
2433 2422 /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2434 2423 status = i_ipadm_validate_create_addr(iph, addr, flags);
2435 - if (status != IPADM_SUCCESS)
2424 + if (status != IPADM_SUCCESS) {
2436 2425 return (status);
2437 -
2426 + }
2438 2427 /*
2439 2428 * For Legacy case, check if an addrobj already exists for the
2440 2429 * given logical interface name. If one does not exist,
2441 2430 * a default name will be generated and added to the daemon's
2442 2431 * aobjmap.
2443 2432 */
2444 2433 if (legacy) {
2445 2434 struct ipadm_addrobj_s ipaddr;
2446 2435
2447 2436 ipaddr = *addr;
2448 2437 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2449 2438 if (status == IPADM_SUCCESS) {
2450 2439 aobjfound = B_TRUE;
2451 2440 /*
2452 2441 * With IPH_LEGACY, modifying an address that is not
2453 2442 * a static address will return with an error.
2454 2443 */
2455 2444 if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2456 2445 return (IPADM_NOTSUP);
2457 2446 /*
2458 2447 * we found the addrobj in daemon, copy over the
2459 2448 * aobjname to `addr'.
2460 2449 */
2461 2450 (void) strlcpy(addr->ipadm_aobjname,
2462 2451 ipaddr.ipadm_aobjname, IPADM_AOBJSIZ);
2463 2452 } else if (status == IPADM_NOTFOUND) {
2464 2453 aobjfound = B_FALSE;
2465 2454 } else {
2466 2455 return (status);
2467 2456 }
2468 2457 }
2469 2458
2470 2459 af = addr->ipadm_af;
2471 2460 /*
2472 2461 * Create a placeholder for this address object in the daemon.
2473 2462 * Skip this step if we are booting a zone (and therefore being called
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
2474 2463 * from ipmgmtd itself), and, for IPH_LEGACY case if the
2475 2464 * addrobj already exists.
2476 2465 *
2477 2466 * Note that the placeholder is not needed in the NGZ boot case,
2478 2467 * when zoneadmd has itself applied the "allowed-ips" property to clamp
2479 2468 * down any interface configuration, so the namespace for the interface
2480 2469 * is fully controlled by the GZ.
2481 2470 */
2482 2471 if (!is_boot && (!legacy || !aobjfound)) {
2483 2472 status = i_ipadm_lookupadd_addrobj(iph, addr);
2484 - if (status != IPADM_SUCCESS)
2473 + if (status != IPADM_SUCCESS) {
2485 2474 return (status);
2475 + }
2486 2476 }
2487 2477
2488 2478 is_6to4 = i_ipadm_is_6to4(iph, ifname);
2489 2479 /* Plumb the IP interfaces if necessary */
2490 2480 status = i_ipadm_create_if(iph, ifname, af, flags);
2491 2481 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2492 2482 (void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
2493 2483 return (status);
2494 2484 }
2495 2485 if (status == IPADM_SUCCESS)
2496 2486 created_af = B_TRUE;
2497 2487 if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) {
2498 2488 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
2499 2489 status = i_ipadm_create_if(iph, ifname, other_af, flags);
2500 2490 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2501 2491 (void) i_ipadm_delete_if(iph, ifname, af, flags);
2502 2492 return (status);
2503 2493 }
2504 2494 if (status == IPADM_SUCCESS)
2505 2495 created_other_af = B_TRUE;
2506 2496 }
2507 2497
2508 2498 /*
2509 2499 * Some input validation based on the interface flags:
2510 2500 * 1. in non-global zones, make sure that we are not persistently
2511 2501 * creating addresses on interfaces that are acquiring
2512 2502 * address from the global zone.
2513 2503 * 2. Validate static addresses for IFF_POINTOPOINT interfaces.
2514 2504 */
2515 2505 if (addr->ipadm_atype == IPADM_ADDR_STATIC) {
2516 2506 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
2517 2507 if (status != IPADM_SUCCESS)
2518 2508 goto fail;
2519 2509
2520 2510 if (iph->iph_zoneid != GLOBAL_ZONEID &&
2521 2511 (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) {
2522 2512 status = IPADM_GZ_PERM;
2523 2513 goto fail;
2524 2514 }
2525 2515 daf = addr->ipadm_static_dst_addr.ss_family;
2526 2516 if (ifflags & IFF_POINTOPOINT) {
2527 2517 if (is_6to4) {
2528 2518 if (af != AF_INET6 || daf != AF_UNSPEC) {
2529 2519 status = IPADM_INVALID_ARG;
2530 2520 goto fail;
2531 2521 }
2532 2522 } else {
2533 2523 if (daf != af) {
2534 2524 status = IPADM_INVALID_ARG;
2535 2525 goto fail;
2536 2526 }
2537 2527 /* Check for a valid dst address. */
2538 2528 if (!legacy && sockaddrunspec(
2539 2529 (struct sockaddr *)
2540 2530 &addr->ipadm_static_dst_addr)) {
2541 2531 status = IPADM_BAD_ADDR;
2542 2532 goto fail;
2543 2533 }
2544 2534 }
2545 2535 } else {
2546 2536 /*
2547 2537 * Disallow setting of dstaddr when the link is not
2548 2538 * a point-to-point link.
2549 2539 */
2550 2540 if (daf != AF_UNSPEC)
2551 2541 return (IPADM_INVALID_ARG);
2552 2542 }
2553 2543 }
2554 2544
2555 2545 /*
2556 2546 * For 6to4 interfaces, kernel configures a default link-local
2557 2547 * address. We need to replace it, if the caller has provided
2558 2548 * an address that is different from the default link-local.
2559 2549 */
2560 2550 if (status == IPADM_SUCCESS && is_6to4) {
2561 2551 bzero(&lifr, sizeof (lifr));
2562 2552 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2563 2553 sizeof (lifr.lifr_name));
2564 2554 if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
2565 2555 status = ipadm_errno2status(errno);
2566 2556 goto fail;
2567 2557 }
2568 2558 if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
2569 2559 return (IPADM_SUCCESS);
2570 2560 }
2571 2561
2572 2562 /* Create the address. */
2573 2563 type = addr->ipadm_atype;
2574 2564 switch (type) {
2575 2565 case IPADM_ADDR_STATIC:
2576 2566 status = i_ipadm_create_addr(iph, addr, flags);
2577 2567 break;
2578 2568 case IPADM_ADDR_DHCP:
2579 2569 status = i_ipadm_create_dhcp(iph, addr, flags);
2580 2570 break;
2581 2571 case IPADM_ADDR_IPV6_ADDRCONF:
2582 2572 status = i_ipadm_create_ipv6addrs(iph, addr, flags);
2583 2573 break;
2584 2574 default:
2585 2575 status = IPADM_INVALID_ARG;
2586 2576 break;
2587 2577 }
2588 2578
2589 2579 /*
2590 2580 * If address was not created successfully, unplumb the interface
2591 2581 * if it was plumbed implicitly in this function and remove the
2592 2582 * addrobj created by the ipmgmtd daemon as a placeholder.
2593 2583 * If IPH_LEGACY is set, then remove the addrobj only if it was
2594 2584 * created in this function.
2595 2585 */
2596 2586 fail:
2597 2587 if (status != IPADM_DHCP_IPC_TIMEOUT &&
2598 2588 status != IPADM_SUCCESS) {
2599 2589 if (!legacy) {
2600 2590 if (created_af || created_other_af) {
2601 2591 if (created_af) {
2602 2592 (void) i_ipadm_delete_if(iph, ifname,
2603 2593 af, flags);
2604 2594 }
2605 2595 if (created_other_af) {
2606 2596 (void) i_ipadm_delete_if(iph, ifname,
2607 2597 other_af, flags);
2608 2598 }
2609 2599 } else {
2610 2600 (void) i_ipadm_delete_addrobj(iph, addr, flags);
2611 2601 }
2612 2602 } else if (!aobjfound) {
2613 2603 (void) i_ipadm_delete_addrobj(iph, addr, flags);
2614 2604 }
2615 2605 }
2616 2606
2617 2607 return (status);
2618 2608 }
2619 2609
2620 2610 /*
2621 2611 * Creates the static address in `ipaddr' in kernel. After successfully
2622 2612 * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
2623 2613 * interface information.
↓ open down ↓ |
128 lines elided |
↑ open up ↑ |
2624 2614 */
2625 2615 static ipadm_status_t
2626 2616 i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
2627 2617 {
2628 2618 struct lifreq lifr;
2629 2619 ipadm_status_t status = IPADM_SUCCESS;
2630 2620 int sock;
2631 2621 struct sockaddr_storage m, *mask = &m;
2632 2622 const struct sockaddr_storage *addr = &ipaddr->ipadm_static_addr;
2633 2623 const struct sockaddr_storage *daddr = &ipaddr->ipadm_static_dst_addr;
2624 + uint32_t iff_flags = IFF_UP;
2634 2625 sa_family_t af;
2635 2626 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2636 2627 struct ipadm_addrobj_s legacy_addr;
2637 2628 boolean_t default_prefixlen = B_FALSE;
2638 2629 boolean_t is_boot;
2639 2630
2640 2631 is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
2641 2632 af = ipaddr->ipadm_af;
2642 2633 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2643 2634
2644 2635 /* If prefixlen was not provided, get default prefixlen */
2645 2636 if (ipaddr->ipadm_static_prefixlen == 0) {
2646 2637 /* prefixlen was not provided, get default prefixlen */
2647 2638 status = i_ipadm_get_default_prefixlen(
2648 2639 &ipaddr->ipadm_static_addr,
2649 2640 &ipaddr->ipadm_static_prefixlen);
2650 2641 if (status != IPADM_SUCCESS)
2651 2642 return (status);
2652 2643 default_prefixlen = B_TRUE;
2653 2644 }
2654 2645 (void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
2655 2646 (struct sockaddr *)mask);
2656 2647
2657 2648 /*
2658 2649 * Create a new logical interface if needed; otherwise, just
2659 2650 * use the 0th logical interface.
2660 2651 */
2661 2652 retry:
2662 2653 if (!(iph->iph_flags & IPH_LEGACY)) {
2663 2654 status = i_ipadm_do_addif(iph, ipaddr);
2664 2655 if (status != IPADM_SUCCESS)
2665 2656 return (status);
2666 2657 /*
2667 2658 * We don't have to set the lifnum for IPH_INIT case, because
2668 2659 * there is no placeholder created for the address object in
2669 2660 * this case. For IPH_LEGACY, we don't do this because the
2670 2661 * lifnum is given by the caller and it will be set in the
2671 2662 * end while we call the i_ipadm_addr_persist().
2672 2663 */
2673 2664 if (!(iph->iph_flags & IPH_INIT)) {
2674 2665 status = i_ipadm_setlifnum_addrobj(iph, ipaddr);
2675 2666 if (status == IPADM_ADDROBJ_EXISTS)
2676 2667 goto retry;
2677 2668 if (status != IPADM_SUCCESS)
2678 2669 return (status);
2679 2670 }
2680 2671 }
2681 2672 i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
2682 2673 sizeof (lifr.lifr_name));
2683 2674 lifr.lifr_addr = *mask;
2684 2675 if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2685 2676 status = ipadm_errno2status(errno);
2686 2677 goto ret;
2687 2678 }
2688 2679 lifr.lifr_addr = *addr;
2689 2680 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2690 2681 status = ipadm_errno2status(errno);
2691 2682 goto ret;
2692 2683 }
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
2693 2684 /* Set the destination address, if one is given. */
2694 2685 if (daddr->ss_family != AF_UNSPEC) {
2695 2686 lifr.lifr_addr = *daddr;
2696 2687 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2697 2688 status = ipadm_errno2status(errno);
2698 2689 goto ret;
2699 2690 }
2700 2691 }
2701 2692
2702 2693 if (flags & IPADM_OPT_UP) {
2703 - status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
2694 + if (i_ipadm_is_under_ipmp(iph, lifr.lifr_name)) {
2695 + iff_flags |= IFF_NOFAILOVER;
2696 + }
2697 + status = i_ipadm_set_flags(iph, lifr.lifr_name, af, iff_flags, 0);
2704 2698
2705 2699 /*
2706 2700 * IPADM_DAD_FOUND is a soft-error for create-addr.
2707 2701 * No need to tear down the address.
2708 2702 */
2709 2703 if (status == IPADM_DAD_FOUND)
2710 2704 status = IPADM_SUCCESS;
2711 2705 }
2712 2706
2713 2707 if (status == IPADM_SUCCESS && !is_boot) {
2714 2708 /*
2715 2709 * For IPH_LEGACY, we might be modifying the address on
2716 2710 * an address object that already exists e.g. by doing
2717 2711 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2718 2712 * So, we need to store the object only if it does not
2719 2713 * already exist in ipmgmtd.
2720 2714 */
2721 2715 if (legacy) {
2722 2716 bzero(&legacy_addr, sizeof (legacy_addr));
2723 2717 (void) strlcpy(legacy_addr.ipadm_aobjname,
2724 2718 ipaddr->ipadm_aobjname,
2725 2719 sizeof (legacy_addr.ipadm_aobjname));
2726 2720 status = i_ipadm_get_addrobj(iph, &legacy_addr);
2727 2721 if (status == IPADM_SUCCESS &&
2728 2722 legacy_addr.ipadm_lifnum >= 0) {
2729 2723 return (status);
2730 2724 }
2731 2725 }
2732 2726 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2733 2727 flags);
2734 2728 }
2735 2729 ret:
2736 2730 if (status != IPADM_SUCCESS && !legacy)
2737 2731 (void) i_ipadm_delete_addr(iph, ipaddr);
2738 2732 return (status);
2739 2733 }
2740 2734
2741 2735 /*
2742 2736 * Removes the address object identified by `aobjname' from both active and
2743 2737 * persistent configuration. The address object will be removed from only
2744 2738 * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2745 2739 *
2746 2740 * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2747 2741 * in the address object will be removed from the physical interface.
2748 2742 * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2749 2743 * whether the lease should be released. If IPADM_OPT_RELEASE is not
2750 2744 * specified, the lease will be dropped. This option is not supported
2751 2745 * for other address types.
2752 2746 *
2753 2747 * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
2754 2748 * all the autoconfigured addresses will be removed.
2755 2749 * Finally, the address object is also removed from ipmgmtd's aobjmap and from
2756 2750 * the persistent DB.
2757 2751 */
2758 2752 ipadm_status_t
2759 2753 ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
2760 2754 {
2761 2755 ipadm_status_t status;
2762 2756 struct ipadm_addrobj_s ipaddr;
2763 2757 boolean_t release = ((flags & IPADM_OPT_RELEASE) != 0);
2764 2758
2765 2759 /* check for solaris.network.interface.config authorization */
2766 2760 if (!ipadm_check_auth())
2767 2761 return (IPADM_EAUTH);
2768 2762
2769 2763 /* validate input */
2770 2764 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
2771 2765 !(flags & IPADM_OPT_ACTIVE)) ||
2772 2766 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) {
2773 2767 return (IPADM_INVALID_ARG);
2774 2768 }
2775 2769 bzero(&ipaddr, sizeof (ipaddr));
2776 2770 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
2777 2771 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
2778 2772 return (IPADM_INVALID_ARG);
2779 2773 }
2780 2774
2781 2775 /* Retrieve the address object information from ipmgmtd. */
2782 2776 status = i_ipadm_get_addrobj(iph, &ipaddr);
2783 2777 if (status != IPADM_SUCCESS)
2784 2778 return (status);
2785 2779
2786 2780 if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
2787 2781 return (IPADM_NOTSUP);
2788 2782 /*
2789 2783 * If requested to delete just from active config but the address
2790 2784 * is not in active config, return error.
2791 2785 */
2792 2786 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
2793 2787 (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
2794 2788 return (IPADM_NOTFOUND);
2795 2789 }
2796 2790
2797 2791 /*
2798 2792 * If address is present in active config, remove it from
2799 2793 * kernel.
2800 2794 */
2801 2795 if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
2802 2796 switch (ipaddr.ipadm_atype) {
2803 2797 case IPADM_ADDR_STATIC:
2804 2798 status = i_ipadm_delete_addr(iph, &ipaddr);
2805 2799 break;
2806 2800 case IPADM_ADDR_DHCP:
2807 2801 status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
2808 2802 break;
2809 2803 case IPADM_ADDR_IPV6_ADDRCONF:
2810 2804 status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
2811 2805 break;
2812 2806 default:
2813 2807 /*
2814 2808 * This is the case of address object name residing in
2815 2809 * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
2816 2810 * through and delete that address object.
2817 2811 */
2818 2812 break;
2819 2813 }
2820 2814
2821 2815 /*
2822 2816 * If the address was previously deleted from the active
2823 2817 * config, we will get a IPADM_ENXIO from kernel.
2824 2818 * We will still proceed and purge the address information
2825 2819 * in the DB.
2826 2820 */
2827 2821 if (status == IPADM_ENXIO)
2828 2822 status = IPADM_SUCCESS;
2829 2823 else if (status != IPADM_SUCCESS)
2830 2824 return (status);
2831 2825 }
2832 2826
2833 2827 if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
2834 2828 (flags & IPADM_OPT_PERSIST)) {
2835 2829 flags &= ~IPADM_OPT_PERSIST;
2836 2830 }
2837 2831 status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
2838 2832 if (status == IPADM_NOTFOUND)
2839 2833 return (status);
2840 2834 return (IPADM_SUCCESS);
2841 2835 }
2842 2836
2843 2837 /*
2844 2838 * Starts the dhcpagent and sends it the message DHCP_START to start
2845 2839 * configuring a dhcp address on the given interface in `addr'.
2846 2840 * After making the dhcpagent request, it also updates the
2847 2841 * address object information in ipmgmtd's aobjmap and creates an
2848 2842 * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'.
2849 2843 */
2850 2844 static ipadm_status_t
2851 2845 i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2852 2846 {
2853 2847 ipadm_status_t status;
2854 2848 ipadm_status_t dh_status;
2855 2849
2856 2850 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
2857 2851 return (IPADM_DHCP_START_ERROR);
2858 2852 /*
2859 2853 * Create a new logical interface if needed; otherwise, just
2860 2854 * use the 0th logical interface.
2861 2855 */
2862 2856 retry:
2863 2857 status = i_ipadm_do_addif(iph, addr);
2864 2858 if (status != IPADM_SUCCESS)
2865 2859 return (status);
2866 2860 /*
2867 2861 * We don't have to set the lifnum for IPH_INIT case, because
2868 2862 * there is no placeholder created for the address object in this
2869 2863 * case.
2870 2864 */
2871 2865 if (!(iph->iph_flags & IPH_INIT)) {
2872 2866 status = i_ipadm_setlifnum_addrobj(iph, addr);
2873 2867 if (status == IPADM_ADDROBJ_EXISTS)
2874 2868 goto retry;
2875 2869 if (status != IPADM_SUCCESS)
2876 2870 return (status);
2877 2871 }
2878 2872 /* Send DHCP_START to the dhcpagent. */
2879 2873 status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
2880 2874 /*
2881 2875 * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
2882 2876 * since it is only a soft error to indicate the caller that the lease
2883 2877 * might be required after the function returns.
2884 2878 */
2885 2879 if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
2886 2880 goto fail;
2887 2881 dh_status = status;
2888 2882
2889 2883 /* Persist the address object information in ipmgmtd. */
2890 2884 status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags);
2891 2885 if (status != IPADM_SUCCESS)
2892 2886 goto fail;
2893 2887
2894 2888 return (dh_status);
2895 2889 fail:
2896 2890 /* In case of error, delete the dhcp address */
2897 2891 (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
2898 2892 return (status);
2899 2893 }
2900 2894
2901 2895 /*
2902 2896 * Releases/drops the dhcp lease on the logical interface in the address
2903 2897 * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
2904 2898 */
2905 2899 static ipadm_status_t
2906 2900 i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
2907 2901 {
2908 2902 ipadm_status_t status;
2909 2903 int dherr;
2910 2904
2911 2905 /* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */
2912 2906 if (release) {
2913 2907 status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr);
2914 2908 /*
2915 2909 * If no lease was obtained on the object, we should
2916 2910 * drop the dhcp control on the interface.
2917 2911 */
2918 2912 if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE)
2919 2913 status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
2920 2914 } else {
2921 2915 status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
2922 2916 }
2923 2917 if (status != IPADM_SUCCESS)
2924 2918 return (status);
2925 2919
2926 2920 /* Delete the logical interface */
2927 2921 if (addr->ipadm_lifnum != 0) {
2928 2922 struct lifreq lifr;
2929 2923
2930 2924 bzero(&lifr, sizeof (lifr));
2931 2925 i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
2932 2926 sizeof (lifr.lifr_name));
2933 2927 if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
2934 2928 return (ipadm_errno2status(errno));
2935 2929 }
2936 2930
2937 2931 return (IPADM_SUCCESS);
2938 2932 }
2939 2933
2940 2934 /*
2941 2935 * Communicates with the dhcpagent to send a dhcp message of type `type'.
2942 2936 * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
2943 2937 * in `dhcperror'.
2944 2938 */
2945 2939 static ipadm_status_t
2946 2940 i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
2947 2941 {
2948 2942 dhcp_ipc_request_t *request;
2949 2943 dhcp_ipc_reply_t *reply = NULL;
2950 2944 char ifname[LIFNAMSIZ];
2951 2945 int error;
2952 2946 int dhcp_timeout;
2953 2947
2954 2948 /* Construct a message to the dhcpagent. */
2955 2949 bzero(&ifname, sizeof (ifname));
2956 2950 i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
2957 2951 if (addr->ipadm_primary)
2958 2952 type |= DHCP_PRIMARY;
2959 2953 request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
2960 2954 if (request == NULL)
2961 2955 return (IPADM_NO_MEMORY);
2962 2956
2963 2957 if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
2964 2958 dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
2965 2959 else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
2966 2960 dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
2967 2961 else
2968 2962 dhcp_timeout = addr->ipadm_wait;
2969 2963 /* Send the message to dhcpagent. */
2970 2964 error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
2971 2965 free(request);
2972 2966 if (error == 0) {
2973 2967 error = reply->return_code;
2974 2968 free(reply);
2975 2969 }
2976 2970 if (error != 0) {
2977 2971 if (dhcperror != NULL)
2978 2972 *dhcperror = error;
2979 2973 if (error != DHCP_IPC_E_TIMEOUT)
2980 2974 return (IPADM_DHCP_IPC_ERROR);
2981 2975 else if (dhcp_timeout != 0)
2982 2976 return (IPADM_DHCP_IPC_TIMEOUT);
2983 2977 }
2984 2978
2985 2979 return (IPADM_SUCCESS);
2986 2980 }
2987 2981
2988 2982 /*
2989 2983 * Returns the IP addresses of the specified interface in both the
2990 2984 * active and the persistent configuration. If no
2991 2985 * interface is specified, it returns all non-zero IP addresses
2992 2986 * configured on all interfaces in active and persistent
2993 2987 * configurations.
2994 2988 * `addrinfo' will contain addresses that are
2995 2989 * (1) in both active and persistent configuration (created persistently)
2996 2990 * (2) only in active configuration (created temporarily)
2997 2991 * (3) only in persistent configuration (disabled addresses)
2998 2992 *
2999 2993 * Address list that is returned by this function must be freed
3000 2994 * using the ipadm_freeaddr_info() function.
3001 2995 */
3002 2996 ipadm_status_t
3003 2997 ipadm_addr_info(ipadm_handle_t iph, const char *ifname,
3004 2998 ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags)
3005 2999 {
3006 3000 ifspec_t ifsp;
3007 3001
3008 3002 if (addrinfo == NULL || iph == NULL)
3009 3003 return (IPADM_INVALID_ARG);
3010 3004 if (ifname != NULL &&
3011 3005 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
3012 3006 return (IPADM_INVALID_ARG);
3013 3007 }
3014 3008 return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
3015 3009 flags, lifc_flags));
3016 3010 }
3017 3011
3018 3012 /*
3019 3013 * Frees the structure allocated by ipadm_addr_info().
3020 3014 */
3021 3015 void
3022 3016 ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
3023 3017 {
3024 3018 freeifaddrs((struct ifaddrs *)ainfo);
3025 3019 }
3026 3020
3027 3021 /*
3028 3022 * Makes a door call to ipmgmtd to update its `aobjmap' with the address
3029 3023 * object in `ipaddr'. This door call also updates the persistent DB to
3030 3024 * remember address object to be recreated on next reboot or on an
3031 3025 * ipadm_enable_addr()/ipadm_enable_if() call.
3032 3026 */
3033 3027 ipadm_status_t
3034 3028 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3035 3029 boolean_t default_prefixlen, uint32_t flags)
3036 3030 {
3037 3031 char *aname = ipaddr->ipadm_aobjname;
3038 3032 nvlist_t *nvl;
3039 3033 int err = 0;
3040 3034 ipadm_status_t status;
3041 3035 char pval[MAXPROPVALLEN];
3042 3036 uint_t pflags = 0;
3043 3037 ipadm_prop_desc_t *pdp = NULL;
3044 3038
3045 3039 /*
3046 3040 * Construct the nvl to send to the door.
3047 3041 */
3048 3042 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3049 3043 return (IPADM_NO_MEMORY);
3050 3044 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
3051 3045 ipaddr->ipadm_ifname)) != 0 ||
3052 3046 (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
3053 3047 (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
3054 3048 ipaddr->ipadm_lifnum)) != 0) {
3055 3049 status = ipadm_errno2status(err);
3056 3050 goto ret;
3057 3051 }
3058 3052 switch (ipaddr->ipadm_atype) {
3059 3053 case IPADM_ADDR_STATIC:
3060 3054 status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
3061 3055 if (status != IPADM_SUCCESS)
3062 3056 goto ret;
3063 3057 (void) snprintf(pval, sizeof (pval), "%d",
3064 3058 ipaddr->ipadm_static_prefixlen);
3065 3059 if (flags & IPADM_OPT_UP)
3066 3060 err = nvlist_add_string(nvl, "up", "yes");
3067 3061 else
3068 3062 err = nvlist_add_string(nvl, "up", "no");
3069 3063 status = ipadm_errno2status(err);
3070 3064 break;
3071 3065 case IPADM_ADDR_DHCP:
3072 3066 status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
3073 3067 ipaddr->ipadm_wait);
3074 3068 break;
3075 3069 case IPADM_ADDR_IPV6_ADDRCONF:
3076 3070 status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
3077 3071 break;
3078 3072 }
3079 3073 if (status != IPADM_SUCCESS)
3080 3074 goto ret;
3081 3075
3082 3076 if (iph->iph_flags & IPH_INIT) {
3083 3077 /*
3084 3078 * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
3085 3079 * IPMGMT_PERSIST on the address object in its `aobjmap'.
3086 3080 * For the callers ipadm_enable_if() and ipadm_enable_addr(),
3087 3081 * IPADM_OPT_PERSIST is not set in their flags. They send
3088 3082 * IPH_INIT in iph_flags, so that the address object will be
3089 3083 * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
3090 3084 */
3091 3085 pflags |= IPMGMT_INIT;
3092 3086 } else {
3093 3087 if (flags & IPADM_OPT_ACTIVE)
3094 3088 pflags |= IPMGMT_ACTIVE;
3095 3089 if (flags & IPADM_OPT_PERSIST)
3096 3090 pflags |= IPMGMT_PERSIST;
3097 3091 }
3098 3092 status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
3099 3093 /*
3100 3094 * prefixlen is stored in a separate line in the DB and not along
3101 3095 * with the address itself, since it is also an address property and
3102 3096 * all address properties are stored in separate lines. We need to
3103 3097 * persist the prefixlen by calling the function that persists
3104 3098 * address properties.
3105 3099 */
3106 3100 if (status == IPADM_SUCCESS && !default_prefixlen &&
3107 3101 ipaddr->ipadm_atype == IPADM_ADDR_STATIC &&
3108 3102 (flags & IPADM_OPT_PERSIST)) {
3109 3103 for (pdp = ipadm_addrprop_table; pdp->ipd_name != NULL; pdp++) {
3110 3104 if (strcmp("prefixlen", pdp->ipd_name) == 0)
3111 3105 break;
3112 3106 }
3113 3107 assert(pdp != NULL);
3114 3108 status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);
3115 3109 }
3116 3110 ret:
3117 3111 nvlist_free(nvl);
3118 3112 return (status);
3119 3113 }
3120 3114
3121 3115 /*
3122 3116 * Makes the door call to ipmgmtd to store the address object in the
3123 3117 * nvlist `nvl'.
3124 3118 */
3125 3119 static ipadm_status_t
3126 3120 i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
3127 3121 {
3128 3122 char *buf = NULL, *nvlbuf = NULL;
3129 3123 size_t nvlsize, bufsize;
3130 3124 ipmgmt_setaddr_arg_t *sargp;
3131 3125 int err;
3132 3126
3133 3127 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
3134 3128 if (err != 0)
3135 3129 return (ipadm_errno2status(err));
3136 3130 bufsize = sizeof (*sargp) + nvlsize;
3137 3131 buf = calloc(1, bufsize);
3138 3132 sargp = (void *)buf;
3139 3133 sargp->ia_cmd = IPMGMT_CMD_SETADDR;
3140 3134 sargp->ia_flags = flags;
3141 3135 sargp->ia_nvlsize = nvlsize;
3142 3136 (void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize);
3143 3137 err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE);
3144 3138 free(buf);
3145 3139 free(nvlbuf);
3146 3140 return (ipadm_errno2status(err));
3147 3141 }
3148 3142
3149 3143 /*
3150 3144 * Makes a door call to ipmgmtd to remove the address object in `ipaddr'
3151 3145 * from its `aobjmap'. This door call also removes the address object and all
3152 3146 * its properties from the persistent DB if IPADM_OPT_PERSIST is set in
3153 3147 * `flags', so that the object will not be recreated on next reboot or on an
3154 3148 * ipadm_enable_addr()/ipadm_enable_if() call.
3155 3149 */
3156 3150 ipadm_status_t
3157 3151 i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3158 3152 uint32_t flags)
3159 3153 {
3160 3154 ipmgmt_addr_arg_t arg;
3161 3155 int err;
3162 3156
3163 3157 arg.ia_cmd = IPMGMT_CMD_RESETADDR;
3164 3158 arg.ia_flags = 0;
3165 3159 if (flags & IPADM_OPT_ACTIVE)
3166 3160 arg.ia_flags |= IPMGMT_ACTIVE;
3167 3161 if (flags & IPADM_OPT_PERSIST)
3168 3162 arg.ia_flags |= IPMGMT_PERSIST;
3169 3163 (void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname,
3170 3164 sizeof (arg.ia_aobjname));
3171 3165 arg.ia_lnum = ipaddr->ipadm_lifnum;
3172 3166 err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE);
3173 3167 return (ipadm_errno2status(err));
3174 3168 }
3175 3169
3176 3170 /*
3177 3171 * Checks if the caller is authorized for the up/down operation.
3178 3172 * Retrieves the address object corresponding to `aobjname' from ipmgmtd
3179 3173 * and retrieves the address flags for that object from kernel.
3180 3174 * The arguments `ipaddr' and `ifflags' must be allocated by the caller.
3181 3175 */
3182 3176 static ipadm_status_t
3183 3177 i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname,
3184 3178 ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags)
3185 3179 {
3186 3180 ipadm_status_t status;
3187 3181 char lifname[LIFNAMSIZ];
3188 3182
3189 3183 /* check for solaris.network.interface.config authorization */
3190 3184 if (!ipadm_check_auth())
3191 3185 return (IPADM_EAUTH);
3192 3186
3193 3187 /* validate input */
3194 3188 if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3195 3189 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
↓ open down ↓ |
482 lines elided |
↑ open up ↑ |
3196 3190 return (IPADM_INVALID_ARG);
3197 3191 }
3198 3192
3199 3193 /* Retrieve the address object information. */
3200 3194 status = i_ipadm_get_addrobj(iph, ipaddr);
3201 3195 if (status != IPADM_SUCCESS)
3202 3196 return (status);
3203 3197
3204 3198 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3205 3199 return (IPADM_OP_DISABLE_OBJ);
3200 +
3206 3201 if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3207 3202 !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3208 3203 return (IPADM_TEMPORARY_OBJ);
3204 +
3209 3205 if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3210 3206 (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3211 3207 (ipadm_flags & IPADM_OPT_PERSIST)))
3212 3208 return (IPADM_NOTSUP);
3213 3209
3214 3210 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3211 +
3215 3212 return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3216 3213 }
3217 3214
3218 3215 /*
3219 3216 * Marks the address in the address object `aobjname' up. This operation is
3220 3217 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3221 3218 * For an address object of type IPADM_ADDR_DHCP, this operation can
3222 3219 * only be temporary and no updates will be made to the persistent DB.
3223 3220 */
3224 3221 ipadm_status_t
3225 3222 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3226 3223 {
3227 3224 struct ipadm_addrobj_s ipaddr;
3228 3225 ipadm_status_t status;
3229 3226 uint64_t flags;
3230 3227 char lifname[LIFNAMSIZ];
3231 3228
3232 3229 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3233 3230 &flags);
3234 3231 if (status != IPADM_SUCCESS)
3235 3232 return (status);
3236 3233 if (flags & IFF_UP)
3237 3234 goto persist;
3238 3235 /*
3239 3236 * If the address is already a duplicate, then refresh-addr
3240 3237 * should be used to mark it up.
3241 3238 */
3242 3239 if (flags & IFF_DUPLICATE)
3243 3240 return (IPADM_DAD_FOUND);
3244 3241
3245 3242 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3246 3243 status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0);
3247 3244 if (status != IPADM_SUCCESS)
3248 3245 return (status);
3249 3246
3250 3247 persist:
3251 3248 /* Update persistent DB. */
3252 3249 if (ipadm_flags & IPADM_OPT_PERSIST) {
3253 3250 status = i_ipadm_persist_propval(iph, &up_addrprop,
3254 3251 "yes", &ipaddr, 0);
3255 3252 }
3256 3253
3257 3254 return (status);
3258 3255 }
3259 3256
3260 3257 /*
3261 3258 * Marks the address in the address object `aobjname' down. This operation is
3262 3259 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3263 3260 * For an address object of type IPADM_ADDR_DHCP, this operation can
3264 3261 * only be temporary and no updates will be made to the persistent DB.
3265 3262 */
3266 3263 ipadm_status_t
3267 3264 ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3268 3265 {
3269 3266 struct ipadm_addrobj_s ipaddr;
3270 3267 ipadm_status_t status;
3271 3268 struct lifreq lifr;
3272 3269 uint64_t flags;
3273 3270
3274 3271 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3275 3272 &flags);
3276 3273 if (status != IPADM_SUCCESS)
3277 3274 return (status);
3278 3275 i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name,
3279 3276 sizeof (lifr.lifr_name));
3280 3277 if (flags & IFF_UP) {
3281 3278 status = i_ipadm_set_flags(iph, lifr.lifr_name,
3282 3279 ipaddr.ipadm_af, 0, IFF_UP);
3283 3280 if (status != IPADM_SUCCESS)
3284 3281 return (status);
3285 3282 } else if (flags & IFF_DUPLICATE) {
3286 3283 /*
3287 3284 * Clear the IFF_DUPLICATE flag.
3288 3285 */
3289 3286 if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0)
3290 3287 return (ipadm_errno2status(errno));
3291 3288 if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0)
3292 3289 return (ipadm_errno2status(errno));
3293 3290 }
3294 3291
3295 3292 /* Update persistent DB */
3296 3293 if (ipadm_flags & IPADM_OPT_PERSIST) {
3297 3294 status = i_ipadm_persist_propval(iph, &up_addrprop,
3298 3295 "no", &ipaddr, 0);
3299 3296 }
3300 3297
3301 3298 return (status);
3302 3299 }
3303 3300
3304 3301 /*
3305 3302 * Refreshes the address in the address object `aobjname'. If the address object
3306 3303 * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
3307 3304 * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
3308 3305 * dhcpagent for this static address. If the address object is of type
3309 3306 * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
3310 3307 * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
3311 3308 * dhcpagent. This operation is not supported for an address object of
3312 3309 * type IPADM_ADDR_IPV6_ADDRCONF.
3313 3310 */
3314 3311 ipadm_status_t
3315 3312 ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
3316 3313 uint32_t ipadm_flags)
3317 3314 {
3318 3315 ipadm_status_t status = IPADM_SUCCESS;
3319 3316 uint64_t flags;
3320 3317 struct ipadm_addrobj_s ipaddr;
3321 3318 sa_family_t af;
3322 3319 char lifname[LIFNAMSIZ];
3323 3320 boolean_t inform =
3324 3321 ((ipadm_flags & IPADM_OPT_INFORM) != 0);
3325 3322 int dherr;
3326 3323
3327 3324 /* check for solaris.network.interface.config authorization */
3328 3325 if (!ipadm_check_auth())
3329 3326 return (IPADM_EAUTH);
3330 3327
3331 3328 bzero(&ipaddr, sizeof (ipaddr));
3332 3329 /* validate input */
3333 3330 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3334 3331 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3335 3332 return (IPADM_INVALID_ARG);
3336 3333 }
3337 3334
3338 3335 /* Retrieve the address object information. */
3339 3336 status = i_ipadm_get_addrobj(iph, &ipaddr);
3340 3337 if (status != IPADM_SUCCESS)
3341 3338 return (status);
3342 3339
3343 3340 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
3344 3341 return (IPADM_OP_DISABLE_OBJ);
3345 3342
3346 3343 if (i_ipadm_is_vni(ipaddr.ipadm_ifname))
3347 3344 return (IPADM_NOTSUP);
3348 3345 if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
3349 3346 return (IPADM_INVALID_ARG);
3350 3347 af = ipaddr.ipadm_af;
3351 3348 if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
3352 3349 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3353 3350 status = i_ipadm_get_flags(iph, lifname, af, &flags);
3354 3351 if (status != IPADM_SUCCESS)
3355 3352 return (status);
3356 3353 if (inform) {
3357 3354 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3358 3355 return (IPADM_DHCP_START_ERROR);
3359 3356
3360 3357 ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3361 3358 return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
3362 3359 }
3363 3360 if (!(flags & IFF_DUPLICATE))
3364 3361 return (IPADM_SUCCESS);
3365 3362 status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
3366 3363 } else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
3367 3364 status = i_ipadm_op_dhcp(&ipaddr, DHCP_EXTEND, &dherr);
3368 3365 /*
3369 3366 * Restart the dhcp address negotiation with server if no
3370 3367 * address has been acquired yet.
3371 3368 */
3372 3369 if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
3373 3370 ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3374 3371 status = i_ipadm_op_dhcp(&ipaddr, DHCP_START, NULL);
3375 3372 }
3376 3373 } else {
3377 3374 status = IPADM_NOTSUP;
3378 3375 }
3379 3376 return (status);
3380 3377 }
3381 3378
3382 3379 /*
3383 3380 * This is called from ipadm_create_addr() to validate the address parameters.
3384 3381 * It does the following steps:
3385 3382 * 1. Validates the interface name.
3386 3383 * 2. Verifies that the interface is not an IPMP meta-interface or an
3387 3384 * underlying interface.
3388 3385 * 3. In case of a persistent operation, verifies that the interface
3389 3386 * is persistent. Returns error if interface is not enabled but
3390 3387 * is in persistent config.
3391 3388 * 4. Verifies that the destination address is not set or the address type is
3392 3389 * not DHCP or ADDRCONF when the interface is a loopback interface.
3393 3390 * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
3394 3391 * has IFF_VRRP interface flag set.
3395 3392 */
3396 3393 static ipadm_status_t
3397 3394 i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
3398 3395 uint32_t flags)
3399 3396 {
3400 3397 sa_family_t af;
3401 3398 sa_family_t other_af;
3402 3399 char *ifname;
3403 3400 ipadm_status_t status;
3404 3401 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
3405 3402 boolean_t islo, isvni;
3406 3403 uint64_t ifflags = 0;
3407 3404 boolean_t p_exists;
3408 3405 boolean_t af_exists, other_af_exists, a_exists;
3409 3406
3410 3407 if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3411 3408 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3412 3409 return (IPADM_INVALID_ARG);
3413 3410 }
3414 3411
3415 3412 if (ipaddr->ipadm_af == AF_UNSPEC)
↓ open down ↓ |
191 lines elided |
↑ open up ↑ |
3416 3413 return (IPADM_BAD_ADDR);
3417 3414
3418 3415 if (!legacy && ipaddr->ipadm_lifnum != 0)
3419 3416 return (IPADM_INVALID_ARG);
3420 3417
3421 3418 if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3422 3419 return (IPADM_NOTSUP);
3423 3420
3424 3421 ifname = ipaddr->ipadm_ifname;
3425 3422
3426 - if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
3427 - return (IPADM_NOTSUP);
3423 + /*
3424 + * do not go furhter when we are under ipmp.
3425 + * The interface is plumbed up and we are going to add
3426 + * NOFAILOVER address to make in.mpathd happy.
3427 + */
3428 + if (i_ipadm_is_under_ipmp(iph, ifname))
3429 + return (IPADM_SUCCESS);
3428 3430
3429 3431 af = ipaddr->ipadm_af;
3430 3432 af_exists = ipadm_if_enabled(iph, ifname, af);
3431 3433 /*
3432 3434 * For legacy case, interfaces are not implicitly plumbed. We need to
3433 3435 * check if the interface exists in the active configuration.
3434 3436 */
3435 3437 if (legacy && !af_exists)
3436 3438 return (IPADM_ENXIO);
3437 3439
3438 3440 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3439 3441 other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3440 3442 /*
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
3441 3443 * Check if one of the v4 or the v6 interfaces exists in the
3442 3444 * active configuration. An interface is considered disabled only
3443 3445 * if both v4 and v6 are not active.
3444 3446 */
3445 3447 a_exists = (af_exists || other_af_exists);
3446 3448
3447 3449 /* Check if interface exists in the persistent configuration. */
3448 3450 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3449 3451 if (status != IPADM_SUCCESS)
3450 3452 return (status);
3453 +
3451 3454 if (!a_exists && p_exists)
3452 3455 return (IPADM_OP_DISABLE_OBJ);
3453 - if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) {
3454 - /*
3455 - * If address has to be created persistently,
3456 - * and the interface does not exist in the persistent
3457 - * store but in active config, fail.
3458 - */
3459 - return (IPADM_TEMPORARY_OBJ);
3460 - }
3456 +
3461 3457 if (af_exists) {
3462 3458 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3463 3459 if (status != IPADM_SUCCESS)
3464 3460 return (status);
3465 3461 }
3466 3462
3467 3463 /* Perform validation steps (4) and (5) */
3468 3464 islo = i_ipadm_is_loopback(ifname);
3469 3465 isvni = i_ipadm_is_vni(ifname);
3470 3466 switch (ipaddr->ipadm_atype) {
3471 3467 case IPADM_ADDR_STATIC:
3472 3468 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3473 3469 return (IPADM_INVALID_ARG);
3474 3470 /* Check for a valid src address */
3475 3471 if (!legacy && sockaddrunspec(
3476 3472 (struct sockaddr *)&ipaddr->ipadm_static_addr))
3477 3473 return (IPADM_BAD_ADDR);
3478 3474 break;
3479 3475 case IPADM_ADDR_DHCP:
3480 3476 if (islo || (ifflags & IFF_VRRP))
3481 3477 return (IPADM_NOTSUP);
3482 3478 break;
3483 3479 case IPADM_ADDR_IPV6_ADDRCONF:
3484 3480 if (islo || (ifflags & IFF_VRRP) ||
3485 3481 i_ipadm_is_6to4(iph, ifname)) {
3486 3482 return (IPADM_NOTSUP);
3487 3483 }
3488 3484 break;
3489 3485 default:
3490 3486 return (IPADM_INVALID_ARG);
3491 3487 }
3492 3488
3493 3489 return (IPADM_SUCCESS);
3494 3490 }
3495 3491
3496 3492 ipadm_status_t
3497 3493 i_ipadm_merge_prefixlen_from_nvl(nvlist_t *invl, nvlist_t *onvl,
3498 3494 const char *aobjname)
3499 3495 {
3500 3496 nvpair_t *nvp, *prefixnvp;
3501 3497 nvlist_t *tnvl;
3502 3498 char *aname;
3503 3499 int err;
3504 3500
3505 3501 for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
3506 3502 nvp = nvlist_next_nvpair(invl, nvp)) {
3507 3503 if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
3508 3504 nvlist_exists(tnvl, IPADM_NVP_PREFIXLEN) &&
3509 3505 nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
3510 3506 &aname) == 0 && strcmp(aname, aobjname) == 0) {
3511 3507 /* prefixlen exists for given address object */
3512 3508 (void) nvlist_lookup_nvpair(tnvl, IPADM_NVP_PREFIXLEN,
3513 3509 &prefixnvp);
3514 3510 err = nvlist_add_nvpair(onvl, prefixnvp);
3515 3511 if (err == 0) {
3516 3512 err = nvlist_remove(invl, nvpair_name(nvp),
3517 3513 nvpair_type(nvp));
3518 3514 }
3519 3515 return (ipadm_errno2status(err));
3520 3516 }
3521 3517 }
3522 3518 return (IPADM_SUCCESS);
3523 3519 }
3524 3520
3525 3521 /*
3526 3522 * Re-enables the address object `aobjname' based on the saved
3527 3523 * configuration for `aobjname'.
3528 3524 */
3529 3525 ipadm_status_t
3530 3526 ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3531 3527 {
3532 3528 nvlist_t *addrnvl, *nvl;
3533 3529 nvpair_t *nvp;
3534 3530 ipadm_status_t status;
3535 3531 struct ipadm_addrobj_s ipaddr;
3536 3532
3537 3533 /* check for solaris.network.interface.config authorization */
3538 3534 if (!ipadm_check_auth())
3539 3535 return (IPADM_EAUTH);
3540 3536
3541 3537 /* validate input */
3542 3538 if (flags & IPADM_OPT_PERSIST)
3543 3539 return (IPADM_NOTSUP);
3544 3540 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3545 3541 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3546 3542 return (IPADM_INVALID_ARG);
3547 3543 }
3548 3544
3549 3545 /* Retrieve the address object information. */
3550 3546 status = i_ipadm_get_addrobj(iph, &ipaddr);
3551 3547 if (status != IPADM_SUCCESS)
3552 3548 return (status);
3553 3549 if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
3554 3550 return (IPADM_ADDROBJ_EXISTS);
3555 3551
3556 3552 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
3557 3553 if (status != IPADM_SUCCESS)
3558 3554 return (status);
3559 3555
3560 3556 assert(addrnvl != NULL);
3561 3557
3562 3558 for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
3563 3559 nvp = nvlist_next_nvpair(addrnvl, nvp)) {
3564 3560 if (nvpair_value_nvlist(nvp, &nvl) != 0)
3565 3561 continue;
3566 3562
3567 3563 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
3568 3564 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
3569 3565 status = i_ipadm_merge_prefixlen_from_nvl(addrnvl, nvl,
3570 3566 aobjname);
3571 3567 if (status != IPADM_SUCCESS)
3572 3568 continue;
3573 3569 }
3574 3570 iph->iph_flags |= IPH_INIT;
3575 3571 status = i_ipadm_init_addrobj(iph, nvl);
3576 3572 iph->iph_flags &= ~IPH_INIT;
3577 3573 if (status != IPADM_SUCCESS)
3578 3574 break;
3579 3575 }
3580 3576
3581 3577 return (status);
3582 3578 }
3583 3579
3584 3580 /*
3585 3581 * Disables the address object in `aobjname' from the active configuration.
3586 3582 * Error code return values follow the model in ipadm_delete_addr().
3587 3583 */
3588 3584 ipadm_status_t
3589 3585 ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3590 3586 {
3591 3587 /* validate input */
3592 3588 if (flags & IPADM_OPT_PERSIST)
3593 3589 return (IPADM_NOTSUP);
3594 3590
3595 3591 return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE));
3596 3592 }
↓ open down ↓ |
126 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX