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