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]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * This module reads and writes the stable identifier values, DUID and IAID.
39 #include <uuid/uuid.h>
40 #include <sys/types.h>
43 #include <netinet/dhcp6.h>
44 #include <dhcp_inittab.h>
46 #define DUID_FILE "/etc/dhcp/duid"
47 #define IAID_FILE "/etc/dhcp/iaid"
51 char ie_name
[LIFNAMSIZ
];
55 * read_stable_duid(): read the system's stable DUID, if any
57 * input: size_t *: pointer to a size_t to return the DUID length
58 * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set)
59 * note: memory returned is from malloc; caller must free.
63 read_stable_duid(size_t *duidlen
)
70 if ((fd
= open(DUID_FILE
, O_RDONLY
)) == -1)
72 if (fstat(fd
, &sb
) != -1 && S_ISREG(sb
.st_mode
) &&
73 (duid
= malloc(sb
.st_size
)) != NULL
) {
74 retv
= read(fd
, duid
, sb
.st_size
);
75 if (retv
== sb
.st_size
) {
76 *duidlen
= sb
.st_size
;
80 * Make sure that errno always gets set when something
93 * write_stable_duid(): write the system's stable DUID.
95 * input: const uchar_t *: pointer to the DUID buffer
96 * size_t: length of the DUID
97 * output: int: 0 on success, -1 on error. errno is set on error.
101 write_stable_duid(const uchar_t
*duid
, size_t duidlen
)
106 (void) unlink(DUID_FILE
);
107 if ((fd
= open(DUID_FILE
, O_WRONLY
| O_CREAT
, 0644)) == -1)
109 retv
= write(fd
, duid
, duidlen
);
110 if (retv
== duidlen
) {
121 * make_stable_duid(): create a new DUID
123 * input: const char *: name of physical interface for reference
124 * size_t *: pointer to a size_t to return the DUID length
125 * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set)
126 * note: memory returned is from malloc; caller must free.
130 make_stable_duid(const char *physintf
, size_t *duidlen
)
134 dlpi_handle_t dh
= NULL
;
139 * Try to read the MAC layer address for the physical interface
140 * provided as a hint. If that works, we can use a DUID-LLT.
143 if (dlpi_open(physintf
, &dh
, 0) == DLPI_SUCCESS
&&
144 dlpi_bind(dh
, DLPI_ANY_SAP
, NULL
) == DLPI_SUCCESS
&&
145 dlpi_info(dh
, &dlinfo
, 0) == DLPI_SUCCESS
&&
146 (len
= dlinfo
.di_physaddrlen
) > 0 &&
147 (arptype
= dlpi_arptype(dlinfo
.di_mactype
) != 0)) {
151 if ((dllt
= malloc(sizeof (*dllt
) + len
)) == NULL
) {
156 (void) memcpy((dllt
+ 1), dlinfo
.di_physaddr
, len
);
157 dllt
->dllt_dutype
= htons(DHCPV6_DUID_LLT
);
158 dllt
->dllt_hwtype
= htons(arptype
);
159 now
= time(NULL
) - DUID_TIME_BASE
;
160 dllt
->dllt_time
= htonl(now
);
161 *duidlen
= sizeof (*dllt
) + len
;
163 return ((uchar_t
*)dllt
);
169 * If we weren't able to create a DUID based on the network interface
170 * in use, then generate one based on a UUID.
172 den
= malloc(sizeof (*den
) + UUID_LEN
);
176 den
->den_dutype
= htons(DHCPV6_DUID_EN
);
177 DHCPV6_SET_ENTNUM(den
, DHCPV6_SUN_ENT
);
179 (void) memcpy(den
+ 1, uuid
, UUID_LEN
);
180 *duidlen
= sizeof (*den
) + UUID_LEN
;
182 return ((uchar_t
*)den
);
186 * read_stable_iaid(): read a link's stable IAID, if any
188 * input: const char *: interface name
189 * output: uint32_t: the IAID, or 0 if none
193 read_stable_iaid(const char *intf
)
198 if ((fd
= open(IAID_FILE
, O_RDONLY
)) == -1)
200 while (read(fd
, &ie
, sizeof (ie
)) == sizeof (ie
)) {
201 if (strcmp(intf
, ie
.ie_name
) == 0) {
211 * write_stable_iaid(): write out a link's stable IAID
213 * input: const char *: interface name
214 * output: uint32_t: the IAID, or 0 if none
218 write_stable_iaid(const char *intf
, uint32_t iaid
)
224 if ((fd
= open(IAID_FILE
, O_RDWR
| O_CREAT
, 0644)) == -1)
226 while (read(fd
, &ie
, sizeof (ie
)) == sizeof (ie
)) {
227 if (strcmp(intf
, ie
.ie_name
) == 0) {
229 if (iaid
== ie
.ie_iaid
) {
237 (void) memset(&ie
, 0, sizeof (ie
));
239 (void) strlcpy(ie
.ie_name
, intf
, sizeof (ie
.ie_name
));
240 retv
= write(fd
, &ie
, sizeof (ie
));
242 if (retv
== sizeof (ie
)) {
252 * make_stable_iaid(): create a stable IAID for a link
254 * input: const char *: interface name
255 * uint32_t: the ifIndex for this link (as a "hint")
256 * output: uint32_t: the new IAID, never zero
261 make_stable_iaid(const char *intf
, uint32_t hint
)
265 uint32_t maxid
, minunused
;
268 if ((fd
= open(IAID_FILE
, O_RDONLY
)) == -1)
273 * This logic is deliberately unoptimized. The reason is that it runs
274 * essentially just once per interface for the life of the system.
275 * Once the IAID is established, there's no reason to generate it
276 * again, and all we care about here is correctness. Also, IAIDs tend
277 * to get added in a logical sequence order, so the outer loop should
278 * not normally run more than twice.
282 while (read(fd
, &ie
, sizeof (ie
)) == sizeof (ie
)) {
283 if (ie
.ie_iaid
> maxid
)
285 if (ie
.ie_iaid
== minunused
) {
289 if (ie
.ie_iaid
== hint
)
293 (void) lseek(fd
, 0, SEEK_SET
);
298 else if (maxid
!= UINT32_MAX
)