4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
26 * IPMP query interfaces (see PSARC/2002/615 and PSARC/2007/272).
31 #include <libinetutil.h>
35 #include <sys/types.h>
37 #include "ipmp_impl.h"
38 #include "ipmp_mpathd.h"
39 #include "ipmp_query_impl.h"
41 static ipmp_ifinfo_t
*ipmp_ifinfo_clone(ipmp_ifinfo_t
*);
42 static ipmp_addrinfo_t
*ipmp_addrinfo_clone(ipmp_addrinfo_t
*);
43 static ipmp_addrlist_t
*ipmp_addrlist_clone(ipmp_addrlist_t
*);
44 static ipmp_grouplist_t
*ipmp_grouplist_clone(ipmp_grouplist_t
*);
45 static ipmp_groupinfo_t
*ipmp_groupinfo_clone(ipmp_groupinfo_t
*);
46 static ipmp_iflist_t
*ipmp_iflist_create(uint_t
, char (*)[LIFNAMSIZ
]);
47 static void ipmp_freeiflist(ipmp_iflist_t
*);
48 static ipmp_addrlist_t
*ipmp_addrlist_create(uint_t
, struct sockaddr_storage
*);
49 static void ipmp_freeaddrlist(ipmp_addrlist_t
*);
50 static ipmp_groupinfo_t
*ipmp_snap_getgroupinfo(ipmp_snap_t
*, const char *);
51 static ipmp_ifinfo_t
*ipmp_snap_getifinfo(ipmp_snap_t
*, const char *);
52 static ipmp_addrinfo_t
*ipmp_snap_getaddrinfo(ipmp_snap_t
*, const char *,
53 struct sockaddr_storage
*);
54 static int ipmp_snap_take(ipmp_state_t
*, ipmp_snap_t
**);
55 static boolean_t
ipmp_checktlv(ipmp_infotype_t
, size_t, void *);
56 static int ipmp_querydone(ipmp_state_t
*, int);
59 * Using `statep', send a query request for `type' to in.mpathd, and if
60 * necessary wait until at least `endtp' for a response. Returns an IPMP
61 * error code. If successful, the caller may then read additional query
62 * information through ipmp_readinfo(), and must eventually call
63 * ipmp_querydone() to complete the query operation. Only one query may be
64 * outstanding on a given `statep' at a time.
67 ipmp_sendquery(ipmp_state_t
*statep
, ipmp_infotype_t type
, const char *name
,
68 const void *addr
, struct timeval
*endtp
)
74 query
.miq_command
= MI_QUERY
;
75 query
.miq_inforeq
= type
;
79 (void) strlcpy(query
.miq_grname
, name
, LIFGRNAMSIZ
);
80 query
.miq_addr
= *(struct sockaddr_storage
*)addr
;
84 (void) strlcpy(query
.miq_grname
, name
, LIFGRNAMSIZ
);
88 (void) strlcpy(query
.miq_ifname
, name
, LIFNAMSIZ
);
99 if (gettimeofday(endtp
, NULL
) == -1)
100 return (IPMP_FAILURE
);
102 endtp
->tv_sec
+= IPMP_REQTIMEOUT
;
104 assert(statep
->st_fd
== -1);
105 retval
= ipmp_connect(&statep
->st_fd
);
106 if (retval
!= IPMP_SUCCESS
)
109 retval
= ipmp_write(statep
->st_fd
, &query
, sizeof (query
));
110 if (retval
!= IPMP_SUCCESS
)
111 return (ipmp_querydone(statep
, retval
));
113 retval
= ipmp_read(statep
->st_fd
, &result
, sizeof (result
), endtp
);
114 if (retval
!= IPMP_SUCCESS
)
115 return (ipmp_querydone(statep
, retval
));
117 if (result
.me_mpathd_error
!= IPMP_SUCCESS
)
118 return (ipmp_querydone(statep
, result
.me_mpathd_error
));
120 return (IPMP_SUCCESS
);
124 * Using `statep', read a query response of type `infotype' into a dynamically
125 * allocated buffer pointed to by `*infop', before the current time becomes
126 * `endtp'. Returns an IPMP error code.
129 ipmp_readinfo(ipmp_state_t
*statep
, ipmp_infotype_t infotype
, void **infop
,
130 const struct timeval
*endtp
)
134 ipmp_infotype_t type
;
136 retval
= ipmp_readtlv(statep
->st_fd
, &type
, &len
, infop
, endtp
);
137 if (retval
!= IPMP_SUCCESS
)
140 if (type
!= infotype
|| !ipmp_checktlv(type
, len
, *infop
)) {
142 return (IPMP_EPROTO
);
145 return (IPMP_SUCCESS
);
149 * Using `statep', read in the remaining IPMP group information TLVs from
150 * in.mpathd into `grinfop' before the current time becomes `endtp'. Returns
151 * an IPMP error code. On failure, `grinfop' will have its original contents.
154 ipmp_readgroupinfo_lists(ipmp_state_t
*statep
, ipmp_groupinfo_t
*grinfop
,
155 const struct timeval
*endtp
)
158 ipmp_iflist_t
*iflistp
;
159 ipmp_addrlist_t
*adlistp
;
161 retval
= ipmp_readinfo(statep
, IPMP_IFLIST
, (void **)&iflistp
, endtp
);
162 if (retval
!= IPMP_SUCCESS
)
165 retval
= ipmp_readinfo(statep
, IPMP_ADDRLIST
, (void **)&adlistp
, endtp
);
166 if (retval
!= IPMP_SUCCESS
) {
167 ipmp_freeiflist(iflistp
);
171 grinfop
->gr_iflistp
= iflistp
;
172 grinfop
->gr_adlistp
= adlistp
;
173 return (IPMP_SUCCESS
);
177 * Using `statep', read in the remaining IPMP interface information TLVs from
178 * in.mpathd into `ifinfop' before the current time becomes `endtp'. Returns
179 * an IPMP error code. On failure, `ifinfop' will have its original contents.
182 ipmp_readifinfo_lists(ipmp_state_t
*statep
, ipmp_ifinfo_t
*ifinfop
,
183 const struct timeval
*endtp
)
186 ipmp_addrlist_t
*tlist4p
, *tlist6p
;
188 retval
= ipmp_readinfo(statep
, IPMP_ADDRLIST
, (void **)&tlist4p
, endtp
);
189 if (retval
!= IPMP_SUCCESS
)
192 retval
= ipmp_readinfo(statep
, IPMP_ADDRLIST
, (void **)&tlist6p
, endtp
);
193 if (retval
!= IPMP_SUCCESS
) {
194 ipmp_freeaddrlist(tlist4p
);
198 ifinfop
->if_targinfo4
.it_targlistp
= tlist4p
;
199 ifinfop
->if_targinfo6
.it_targlistp
= tlist6p
;
200 return (IPMP_SUCCESS
);
204 * Complete the query operation started in ipmp_sendquery(). The interface is
205 * designed to be easy to use in the `return' statement of a function, and
206 * thus returns the passed in `retval' and preserves `errno'.
209 ipmp_querydone(ipmp_state_t
*statep
, int retval
)
213 (void) close(statep
->st_fd
);
220 * Using `handle', get the group list and store the results in a dynamically
221 * allocated buffer pointed to by `*grlistpp'. Returns an IPMP error code.
224 ipmp_getgrouplist(ipmp_handle_t handle
, ipmp_grouplist_t
**grlistpp
)
226 ipmp_state_t
*statep
= handle
;
230 if (statep
->st_snap
!= NULL
) {
231 *grlistpp
= ipmp_grouplist_clone(statep
->st_snap
->sn_grlistp
);
232 return (*grlistpp
!= NULL
? IPMP_SUCCESS
: IPMP_ENOMEM
);
235 retval
= ipmp_sendquery(statep
, IPMP_GROUPLIST
, NULL
, NULL
, &end
);
236 if (retval
!= IPMP_SUCCESS
)
239 retval
= ipmp_readinfo(statep
, IPMP_GROUPLIST
, (void **)grlistpp
, &end
);
240 return (ipmp_querydone(statep
, retval
));
244 * Free the group list pointed to by `grlistp'.
247 ipmp_freegrouplist(ipmp_grouplist_t
*grlistp
)
253 * Using `handle', get the group information associated with group `name' and
254 * store the results in a dynamically allocated buffer pointed to by
255 * `*grinfopp'. Returns an IPMP error code.
258 ipmp_getgroupinfo(ipmp_handle_t handle
, const char *name
,
259 ipmp_groupinfo_t
**grinfopp
)
261 ipmp_state_t
*statep
= handle
;
264 ipmp_groupinfo_t
*grinfop
;
266 if (statep
->st_snap
!= NULL
) {
267 grinfop
= ipmp_snap_getgroupinfo(statep
->st_snap
, name
);
269 return (IPMP_EUNKGROUP
);
271 *grinfopp
= ipmp_groupinfo_clone(grinfop
);
272 return (*grinfopp
!= NULL
? IPMP_SUCCESS
: IPMP_ENOMEM
);
275 retval
= ipmp_sendquery(statep
, IPMP_GROUPINFO
, name
, NULL
, &end
);
276 if (retval
!= IPMP_SUCCESS
)
279 retval
= ipmp_readinfo(statep
, IPMP_GROUPINFO
, (void **)grinfopp
, &end
);
280 if (retval
!= IPMP_SUCCESS
)
281 return (ipmp_querydone(statep
, retval
));
283 retval
= ipmp_readgroupinfo_lists(statep
, *grinfopp
, &end
);
284 if (retval
!= IPMP_SUCCESS
)
287 return (ipmp_querydone(statep
, retval
));
291 * Free the group information pointed to by `grinfop'.
294 ipmp_freegroupinfo(ipmp_groupinfo_t
*grinfop
)
296 ipmp_freeaddrlist(grinfop
->gr_adlistp
);
297 ipmp_freeiflist(grinfop
->gr_iflistp
);
302 * Using `handle', get the interface information associated with interface
303 * `name' and store the results in a dynamically allocated buffer pointed to
304 * by `*ifinfopp'. Returns an IPMP error code.
307 ipmp_getifinfo(ipmp_handle_t handle
, const char *name
, ipmp_ifinfo_t
**ifinfopp
)
309 ipmp_state_t
*statep
= handle
;
310 ipmp_ifinfo_t
*ifinfop
;
314 if (statep
->st_snap
!= NULL
) {
315 ifinfop
= ipmp_snap_getifinfo(statep
->st_snap
, name
);
317 return (IPMP_EUNKIF
);
319 *ifinfopp
= ipmp_ifinfo_clone(ifinfop
);
320 return (*ifinfopp
!= NULL
? IPMP_SUCCESS
: IPMP_ENOMEM
);
323 retval
= ipmp_sendquery(statep
, IPMP_IFINFO
, name
, NULL
, &end
);
324 if (retval
!= IPMP_SUCCESS
)
327 retval
= ipmp_readinfo(statep
, IPMP_IFINFO
, (void **)ifinfopp
, &end
);
328 if (retval
!= IPMP_SUCCESS
)
329 return (ipmp_querydone(statep
, retval
));
331 retval
= ipmp_readifinfo_lists(statep
, *ifinfopp
, &end
);
332 if (retval
!= IPMP_SUCCESS
)
335 return (ipmp_querydone(statep
, retval
));
339 * Free the interface information pointed to by `ifinfop'.
342 ipmp_freeifinfo(ipmp_ifinfo_t
*ifinfop
)
344 ipmp_freeaddrlist(ifinfop
->if_targinfo4
.it_targlistp
);
345 ipmp_freeaddrlist(ifinfop
->if_targinfo6
.it_targlistp
);
350 * Using `handle', get the address information associated with address `addrp'
351 * on group `grname' and store the results in a dynamically allocated buffer
352 * pointed to by `*adinfopp'. Returns an IPMP error code.
355 ipmp_getaddrinfo(ipmp_handle_t handle
, const char *grname
,
356 struct sockaddr_storage
*addrp
, ipmp_addrinfo_t
**adinfopp
)
358 ipmp_state_t
*statep
= handle
;
359 ipmp_addrinfo_t
*adinfop
;
363 if (statep
->st_snap
!= NULL
) {
364 adinfop
= ipmp_snap_getaddrinfo(statep
->st_snap
, grname
, addrp
);
366 return (IPMP_EUNKADDR
);
368 *adinfopp
= ipmp_addrinfo_clone(adinfop
);
369 return (*adinfopp
!= NULL
? IPMP_SUCCESS
: IPMP_ENOMEM
);
372 retval
= ipmp_sendquery(statep
, IPMP_ADDRINFO
, grname
, addrp
, &end
);
373 if (retval
!= IPMP_SUCCESS
)
376 retval
= ipmp_readinfo(statep
, IPMP_ADDRINFO
, (void **)adinfopp
, &end
);
377 return (ipmp_querydone(statep
, retval
));
381 * Free the address information pointed to by `adinfop'.
384 ipmp_freeaddrinfo(ipmp_addrinfo_t
*adinfop
)
390 * Check if `buf' has a NUL byte in its first `bufsize' bytes.
393 hasnulbyte(const char *buf
, size_t bufsize
)
395 while (bufsize
-- > 0) {
396 if (buf
[bufsize
] == '\0')
403 * Check that the TLV triplet named by `type', `len' and `value' is correctly
407 ipmp_checktlv(ipmp_infotype_t type
, size_t len
, void *value
)
409 ipmp_iflist_t
*iflistp
;
410 ipmp_ifinfo_t
*ifinfop
;
411 ipmp_grouplist_t
*grlistp
;
412 ipmp_groupinfo_t
*grinfop
;
413 ipmp_addrlist_t
*adlistp
;
418 if (len
!= sizeof (ipmp_addrinfo_t
))
423 adlistp
= (ipmp_addrlist_t
*)value
;
424 if (len
< IPMP_ADDRLIST_SIZE(0) ||
425 len
< IPMP_ADDRLIST_SIZE(adlistp
->al_naddr
))
430 iflistp
= (ipmp_iflist_t
*)value
;
431 if (len
< IPMP_IFLIST_SIZE(0) ||
432 len
< IPMP_IFLIST_SIZE(iflistp
->il_nif
))
435 for (i
= 0; i
< iflistp
->il_nif
; i
++)
436 if (!hasnulbyte(iflistp
->il_ifs
[i
], LIFNAMSIZ
))
441 ifinfop
= (ipmp_ifinfo_t
*)value
;
442 if (len
!= sizeof (ipmp_ifinfo_t
))
445 if (!hasnulbyte(ifinfop
->if_name
, LIFNAMSIZ
) ||
446 !hasnulbyte(ifinfop
->if_group
, LIFGRNAMSIZ
))
451 grlistp
= (ipmp_grouplist_t
*)value
;
452 if (len
< IPMP_GROUPLIST_SIZE(0) ||
453 len
< IPMP_GROUPLIST_SIZE(grlistp
->gl_ngroup
))
456 for (i
= 0; i
< grlistp
->gl_ngroup
; i
++)
457 if (!hasnulbyte(grlistp
->gl_groups
[i
], LIFGRNAMSIZ
))
462 grinfop
= (ipmp_groupinfo_t
*)value
;
463 if (len
!= sizeof (ipmp_groupinfo_t
))
466 if (!hasnulbyte(grinfop
->gr_name
, LIFGRNAMSIZ
))
471 if (len
!= sizeof (ipmp_snap_t
))
483 * Create a group list; arguments match ipmp_grouplist_t fields. Returns a
484 * pointer to the new group list on success, or NULL on failure.
487 ipmp_grouplist_create(uint64_t sig
, unsigned int ngroup
,
488 char (*groups
)[LIFGRNAMSIZ
])
491 ipmp_grouplist_t
*grlistp
;
493 grlistp
= malloc(IPMP_GROUPLIST_SIZE(ngroup
));
497 grlistp
->gl_sig
= sig
;
498 grlistp
->gl_ngroup
= ngroup
;
499 for (i
= 0; i
< ngroup
; i
++)
500 (void) strlcpy(grlistp
->gl_groups
[i
], groups
[i
], LIFGRNAMSIZ
);
506 * Clone the group list named by `grlistp'. Returns a pointer to the clone on
507 * success, or NULL on failure.
510 ipmp_grouplist_clone(ipmp_grouplist_t
*grlistp
)
512 return (ipmp_grouplist_create(grlistp
->gl_sig
, grlistp
->gl_ngroup
,
513 grlistp
->gl_groups
));
517 * Create target information; arguments match ipmp_targinfo_t fields. Returns
518 * a pointer to the new target info on success, or NULL on failure.
521 ipmp_targinfo_create(const char *name
, struct sockaddr_storage
*testaddrp
,
522 ipmp_if_targmode_t targmode
, uint_t ntarg
, struct sockaddr_storage
*targs
)
524 ipmp_targinfo_t
*targinfop
;
526 targinfop
= malloc(sizeof (ipmp_targinfo_t
));
527 if (targinfop
== NULL
)
530 targinfop
->it_testaddr
= *testaddrp
;
531 targinfop
->it_targmode
= targmode
;
532 targinfop
->it_targlistp
= ipmp_addrlist_create(ntarg
, targs
);
533 if (targinfop
->it_targlistp
== NULL
) {
534 ipmp_freetarginfo(targinfop
);
537 (void) strlcpy(targinfop
->it_name
, name
, LIFNAMSIZ
);
543 * Free the target information pointed to by `targinfop'.
546 ipmp_freetarginfo(ipmp_targinfo_t
*targinfop
)
548 free(targinfop
->it_targlistp
);
553 * Create an interface list; arguments match ipmp_iflist_t fields. Returns a
554 * pointer to the new interface list on success, or NULL on failure.
556 static ipmp_iflist_t
*
557 ipmp_iflist_create(uint_t nif
, char (*ifs
)[LIFNAMSIZ
])
560 ipmp_iflist_t
*iflistp
;
562 iflistp
= malloc(IPMP_IFLIST_SIZE(nif
));
566 iflistp
->il_nif
= nif
;
567 for (i
= 0; i
< nif
; i
++)
568 (void) strlcpy(iflistp
->il_ifs
[i
], ifs
[i
], LIFNAMSIZ
);
574 * Free the interface list pointed to by `iflistp'.
577 ipmp_freeiflist(ipmp_iflist_t
*iflistp
)
583 * Create an interface; arguments match ipmp_ifinfo_t fields. Returns a
584 * pointer to the new interface on success, or NULL on failure.
587 ipmp_ifinfo_create(const char *name
, const char *group
, ipmp_if_state_t state
,
588 ipmp_if_type_t type
, ipmp_if_linkstate_t linkstate
,
589 ipmp_if_probestate_t probestate
, ipmp_if_flags_t flags
,
590 ipmp_targinfo_t
*targinfo4p
, ipmp_targinfo_t
*targinfo6p
)
592 ipmp_ifinfo_t
*ifinfop
;
594 ifinfop
= malloc(sizeof (ipmp_ifinfo_t
));
598 (void) strlcpy(ifinfop
->if_name
, name
, LIFNAMSIZ
);
599 (void) strlcpy(ifinfop
->if_group
, group
, LIFGRNAMSIZ
);
601 ifinfop
->if_state
= state
;
602 ifinfop
->if_type
= type
;
603 ifinfop
->if_linkstate
= linkstate
;
604 ifinfop
->if_probestate
= probestate
;
605 ifinfop
->if_flags
= flags
;
606 ifinfop
->if_targinfo4
= *targinfo4p
;
607 ifinfop
->if_targinfo6
= *targinfo6p
;
609 ifinfop
->if_targinfo4
.it_targlistp
=
610 ipmp_addrlist_clone(targinfo4p
->it_targlistp
);
611 ifinfop
->if_targinfo6
.it_targlistp
=
612 ipmp_addrlist_clone(targinfo6p
->it_targlistp
);
614 if (ifinfop
->if_targinfo4
.it_targlistp
== NULL
||
615 ifinfop
->if_targinfo6
.it_targlistp
== NULL
) {
616 ipmp_freeifinfo(ifinfop
);
624 * Clone the interface information named by `ifinfop'. Returns a pointer to
625 * the clone on success, or NULL on failure.
628 ipmp_ifinfo_clone(ipmp_ifinfo_t
*ifinfop
)
630 return (ipmp_ifinfo_create(ifinfop
->if_name
, ifinfop
->if_group
,
631 ifinfop
->if_state
, ifinfop
->if_type
, ifinfop
->if_linkstate
,
632 ifinfop
->if_probestate
, ifinfop
->if_flags
, &ifinfop
->if_targinfo4
,
633 &ifinfop
->if_targinfo6
));
637 * Create a group; arguments match ipmp_groupinfo_t fields. Returns a pointer
638 * to the new group on success, or NULL on failure.
641 ipmp_groupinfo_create(const char *name
, uint64_t sig
, uint_t fdt
,
642 ipmp_group_state_t state
, uint_t nif
, char (*ifs
)[LIFNAMSIZ
],
643 const char *grifname
, const char *m4ifname
, const char *m6ifname
,
644 const char *bcifname
, uint_t naddr
, struct sockaddr_storage
*addrs
)
646 ipmp_groupinfo_t
*grinfop
;
648 grinfop
= malloc(sizeof (ipmp_groupinfo_t
));
652 grinfop
->gr_sig
= sig
;
653 grinfop
->gr_fdt
= fdt
;
654 grinfop
->gr_state
= state
;
655 grinfop
->gr_iflistp
= ipmp_iflist_create(nif
, ifs
);
656 grinfop
->gr_adlistp
= ipmp_addrlist_create(naddr
, addrs
);
657 if (grinfop
->gr_iflistp
== NULL
|| grinfop
->gr_adlistp
== NULL
) {
658 ipmp_freegroupinfo(grinfop
);
661 (void) strlcpy(grinfop
->gr_name
, name
, LIFGRNAMSIZ
);
662 (void) strlcpy(grinfop
->gr_ifname
, grifname
, LIFNAMSIZ
);
663 (void) strlcpy(grinfop
->gr_m4ifname
, m4ifname
, LIFNAMSIZ
);
664 (void) strlcpy(grinfop
->gr_m6ifname
, m6ifname
, LIFNAMSIZ
);
665 (void) strlcpy(grinfop
->gr_bcifname
, bcifname
, LIFNAMSIZ
);
671 * Clone the group information named by `grinfop'. Returns a pointer to
672 * the clone on success, or NULL on failure.
675 ipmp_groupinfo_clone(ipmp_groupinfo_t
*grinfop
)
677 ipmp_addrlist_t
*adlistp
= grinfop
->gr_adlistp
;
679 return (ipmp_groupinfo_create(grinfop
->gr_name
, grinfop
->gr_sig
,
680 grinfop
->gr_fdt
, grinfop
->gr_state
, grinfop
->gr_iflistp
->il_nif
,
681 grinfop
->gr_iflistp
->il_ifs
, grinfop
->gr_ifname
,
682 grinfop
->gr_m4ifname
, grinfop
->gr_m6ifname
, grinfop
->gr_bcifname
,
683 adlistp
->al_naddr
, adlistp
->al_addrs
));
687 * Create an address list; arguments match ipmp_addrlist_t fields. Returns
688 * a pointer to the new address list on success, or NULL on failure.
690 static ipmp_addrlist_t
*
691 ipmp_addrlist_create(uint_t naddr
, struct sockaddr_storage
*addrs
)
694 ipmp_addrlist_t
*adlistp
;
696 adlistp
= malloc(IPMP_ADDRLIST_SIZE(naddr
));
700 adlistp
->al_naddr
= naddr
;
701 for (i
= 0; i
< naddr
; i
++)
702 adlistp
->al_addrs
[i
] = addrs
[i
];
708 * Clone the address list named by `adlistp'. Returns a pointer to the clone
709 * on success, or NULL on failure.
711 static ipmp_addrlist_t
*
712 ipmp_addrlist_clone(ipmp_addrlist_t
*adlistp
)
714 return (ipmp_addrlist_create(adlistp
->al_naddr
, adlistp
->al_addrs
));
718 * Free the address list pointed to by `adlistp'.
721 ipmp_freeaddrlist(ipmp_addrlist_t
*adlistp
)
727 * Create an address; arguments match ipmp_addrinfo_t fields. Returns a
728 * pointer to the new address on success, or NULL on failure.
731 ipmp_addrinfo_create(struct sockaddr_storage
*addrp
, ipmp_addr_state_t state
,
732 const char *group
, const char *binding
)
734 ipmp_addrinfo_t
*adinfop
;
736 adinfop
= malloc(sizeof (ipmp_addrinfo_t
));
740 adinfop
->ad_addr
= *addrp
;
741 adinfop
->ad_state
= state
;
742 (void) strlcpy(adinfop
->ad_group
, group
, LIFGRNAMSIZ
);
743 (void) strlcpy(adinfop
->ad_binding
, binding
, LIFNAMSIZ
);
749 * Clone the address information named by `adinfop'. Returns a pointer to
750 * the clone on success, or NULL on failure.
753 ipmp_addrinfo_clone(ipmp_addrinfo_t
*adinfop
)
755 return (ipmp_addrinfo_create(&adinfop
->ad_addr
, adinfop
->ad_state
,
756 adinfop
->ad_group
, adinfop
->ad_binding
));
760 * Set the query context associated with `handle' to `qcontext', which must be
761 * either IPMP_QCONTEXT_LIVE or IPMP_QCONTEXT_SNAP. Upon success, any
762 * previous snapshot associated with `handle' is discarded. Returns an IPMP
766 ipmp_setqcontext(ipmp_handle_t handle
, ipmp_qcontext_t qcontext
)
768 ipmp_state_t
*statep
= handle
;
773 case IPMP_QCONTEXT_LIVE
:
777 case IPMP_QCONTEXT_SNAP
:
778 retval
= ipmp_snap_take(statep
, &snap
);
779 if (retval
!= IPMP_SUCCESS
)
784 return (IPMP_EINVAL
);
787 if (statep
->st_snap
!= NULL
)
788 ipmp_snap_free(statep
->st_snap
);
789 statep
->st_snap
= snap
;
791 return (IPMP_SUCCESS
);
795 * Create an empty snapshot. Returns a pointer to the snapshot on success,
796 * or NULL on failure.
799 ipmp_snap_create(void)
803 snap
= malloc(sizeof (ipmp_snap_t
));
807 snap
->sn_grlistp
= NULL
;
808 snap
->sn_grinfolistp
= NULL
;
809 snap
->sn_ifinfolistp
= NULL
;
810 snap
->sn_adinfolistp
= NULL
;
819 * Free all of the resources associated with snapshot `snap'.
822 ipmp_snap_free(ipmp_snap_t
*snap
)
824 ipmp_ifinfolist_t
*iflp
, *ifnext
;
825 ipmp_addrinfolist_t
*adlp
, *adnext
;
826 ipmp_groupinfolist_t
*grlp
, *grnext
;
828 ipmp_freegrouplist(snap
->sn_grlistp
);
830 for (grlp
= snap
->sn_grinfolistp
; grlp
!= NULL
; grlp
= grnext
) {
831 grnext
= grlp
->grl_next
;
832 ipmp_freegroupinfo(grlp
->grl_grinfop
);
836 for (iflp
= snap
->sn_ifinfolistp
; iflp
!= NULL
; iflp
= ifnext
) {
837 ifnext
= iflp
->ifl_next
;
838 ipmp_freeifinfo(iflp
->ifl_ifinfop
);
842 for (adlp
= snap
->sn_adinfolistp
; adlp
!= NULL
; adlp
= adnext
) {
843 adnext
= adlp
->adl_next
;
844 ipmp_freeaddrinfo(adlp
->adl_adinfop
);
852 * Add the group information in `grinfop' to the snapshot named by `snap'.
853 * Returns an IPMP error code.
856 ipmp_snap_addgroupinfo(ipmp_snap_t
*snap
, ipmp_groupinfo_t
*grinfop
)
858 ipmp_groupinfolist_t
*grlp
;
861 * If the information for this group is already in the snapshot,
862 * in.mpathd is broken.
864 if (ipmp_snap_getgroupinfo(snap
, grinfop
->gr_name
) != NULL
)
865 return (IPMP_EPROTO
);
867 grlp
= malloc(sizeof (ipmp_groupinfolist_t
));
869 return (IPMP_ENOMEM
);
871 grlp
->grl_grinfop
= grinfop
;
872 grlp
->grl_next
= snap
->sn_grinfolistp
;
873 snap
->sn_grinfolistp
= grlp
;
876 return (IPMP_SUCCESS
);
880 * Add the interface information in `ifinfop' to the snapshot named by `snap'.
881 * Returns an IPMP error code.
884 ipmp_snap_addifinfo(ipmp_snap_t
*snap
, ipmp_ifinfo_t
*ifinfop
)
886 ipmp_ifinfolist_t
*iflp
;
889 * If the information for this interface is already in the snapshot,
890 * in.mpathd is broken.
892 if (ipmp_snap_getifinfo(snap
, ifinfop
->if_name
) != NULL
)
893 return (IPMP_EPROTO
);
895 iflp
= malloc(sizeof (ipmp_ifinfolist_t
));
897 return (IPMP_ENOMEM
);
899 iflp
->ifl_ifinfop
= ifinfop
;
900 iflp
->ifl_next
= snap
->sn_ifinfolistp
;
901 snap
->sn_ifinfolistp
= iflp
;
904 return (IPMP_SUCCESS
);
908 * Add the address information in `adinfop' to the snapshot named by `snap'.
909 * Returns an IPMP error code.
912 ipmp_snap_addaddrinfo(ipmp_snap_t
*snap
, ipmp_addrinfo_t
*adinfop
)
914 ipmp_addrinfolist_t
*adlp
;
917 * Any duplicate addresses should've already been weeded by in.mpathd.
919 if (ipmp_snap_getaddrinfo(snap
, adinfop
->ad_group
,
920 &adinfop
->ad_addr
) != NULL
)
921 return (IPMP_EPROTO
);
923 adlp
= malloc(sizeof (ipmp_addrinfolist_t
));
925 return (IPMP_ENOMEM
);
927 adlp
->adl_adinfop
= adinfop
;
928 adlp
->adl_next
= snap
->sn_adinfolistp
;
929 snap
->sn_adinfolistp
= adlp
;
932 return (IPMP_SUCCESS
);
936 * Retrieve the information for the group `name' in snapshot `snap'.
937 * Returns a pointer to the group information on success, or NULL on failure.
939 static ipmp_groupinfo_t
*
940 ipmp_snap_getgroupinfo(ipmp_snap_t
*snap
, const char *name
)
942 ipmp_groupinfolist_t
*grlp
;
944 for (grlp
= snap
->sn_grinfolistp
; grlp
!= NULL
; grlp
= grlp
->grl_next
) {
945 if (strcmp(grlp
->grl_grinfop
->gr_name
, name
) == 0)
949 return (grlp
!= NULL
? grlp
->grl_grinfop
: NULL
);
953 * Retrieve the information for the interface `name' in snapshot `snap'.
954 * Returns a pointer to the interface information on success, or NULL on
957 static ipmp_ifinfo_t
*
958 ipmp_snap_getifinfo(ipmp_snap_t
*snap
, const char *name
)
960 ipmp_ifinfolist_t
*iflp
;
962 for (iflp
= snap
->sn_ifinfolistp
; iflp
!= NULL
; iflp
= iflp
->ifl_next
) {
963 if (strcmp(iflp
->ifl_ifinfop
->if_name
, name
) == 0)
967 return (iflp
!= NULL
? iflp
->ifl_ifinfop
: NULL
);
971 * Retrieve the information for the address `addrp' on group `grname' in
972 * snapshot `snap'. Returns a pointer to the address information on success,
973 * or NULL on failure.
975 static ipmp_addrinfo_t
*
976 ipmp_snap_getaddrinfo(ipmp_snap_t
*snap
, const char *grname
,
977 struct sockaddr_storage
*addrp
)
979 ipmp_addrinfolist_t
*adlp
;
981 for (adlp
= snap
->sn_adinfolistp
; adlp
!= NULL
; adlp
= adlp
->adl_next
) {
982 if (strcmp(grname
, adlp
->adl_adinfop
->ad_group
) == 0 &&
983 sockaddrcmp(addrp
, &adlp
->adl_adinfop
->ad_addr
))
987 return (adlp
!= NULL
? adlp
->adl_adinfop
: NULL
);
991 * Using `statep', take a snapshot of the IPMP subsystem and if successful
992 * return it in a dynamically allocated snapshot pointed to by `*snapp'.
993 * Returns an IPMP error code.
996 ipmp_snap_take(ipmp_state_t
*statep
, ipmp_snap_t
**snapp
)
998 ipmp_snap_t
*snap
, *osnap
;
999 ipmp_infotype_t type
;
1005 snap
= ipmp_snap_create();
1007 return (IPMP_ENOMEM
);
1009 retval
= ipmp_sendquery(statep
, IPMP_SNAP
, NULL
, NULL
, &end
);
1010 if (retval
!= IPMP_SUCCESS
) {
1011 ipmp_snap_free(snap
);
1015 retval
= ipmp_readinfo(statep
, IPMP_SNAP
, (void **)&osnap
, &end
);
1016 if (retval
!= IPMP_SUCCESS
) {
1017 ipmp_snap_free(snap
);
1018 return (ipmp_querydone(statep
, retval
));
1022 * Using the information in the `osnap' snapshot, build up our own
1023 * snapshot. We know there will always be at least one TLV (for
1024 * IPMP_GROUPLIST). If we receive anything illogical (e.g., more than
1025 * the expected number of interfaces), then bail out. However, to a
1026 * large extent we have to trust the information sent by in.mpathd.
1030 retval
= ipmp_readtlv(statep
->st_fd
, &type
, &len
, &infop
, &end
);
1031 if (retval
!= IPMP_SUCCESS
)
1034 if (!ipmp_checktlv(type
, len
, infop
)) {
1035 retval
= IPMP_EPROTO
;
1040 case IPMP_GROUPLIST
:
1041 if (snap
->sn_grlistp
!= NULL
) {
1042 retval
= IPMP_EPROTO
;
1045 snap
->sn_grlistp
= infop
;
1049 if (snap
->sn_nif
== osnap
->sn_nif
) {
1050 retval
= IPMP_EPROTO
;
1055 * Read in V4 and V6 targlist TLVs that follow.
1057 retval
= ipmp_readifinfo_lists(statep
, infop
, &end
);
1058 if (retval
!= IPMP_SUCCESS
)
1061 retval
= ipmp_snap_addifinfo(snap
, infop
);
1062 if (retval
!= IPMP_SUCCESS
) {
1063 ipmp_freeifinfo(infop
);
1069 if (snap
->sn_naddr
== osnap
->sn_naddr
) {
1070 retval
= IPMP_EPROTO
;
1074 retval
= ipmp_snap_addaddrinfo(snap
, infop
);
1076 * NOTE: since we didn't call ipmp_read*info_lists(),
1077 * no need to use ipmp_freeaddrinfo() on failure.
1081 case IPMP_GROUPINFO
:
1082 if (snap
->sn_ngroup
== osnap
->sn_ngroup
) {
1083 retval
= IPMP_EPROTO
;
1088 * Read in IPMP groupinfo list TLVs that follow.
1090 retval
= ipmp_readgroupinfo_lists(statep
, infop
, &end
);
1091 if (retval
!= IPMP_SUCCESS
)
1094 retval
= ipmp_snap_addgroupinfo(snap
, infop
);
1095 if (retval
!= IPMP_SUCCESS
) {
1096 ipmp_freegroupinfo(infop
);
1102 retval
= IPMP_EPROTO
;
1106 if (retval
!= IPMP_SUCCESS
) {
1109 ipmp_snap_free(snap
);
1110 return (ipmp_querydone(statep
, retval
));
1112 } while (snap
->sn_grlistp
== NULL
|| snap
->sn_nif
< osnap
->sn_nif
||
1113 snap
->sn_ngroup
< osnap
->sn_ngroup
||
1114 snap
->sn_naddr
< osnap
->sn_naddr
);
1118 return (ipmp_querydone(statep
, IPMP_SUCCESS
));