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