1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This module reads and writes the stable identifier values, DUID and IAID. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <limits.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <libdlpi.h> 41 #include <uuid/uuid.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <net/if.h> 45 #include <netinet/dhcp6.h> 46 #include <dhcp_inittab.h> 47 48 #define DUID_FILE "/etc/dhcp/duid" 49 #define IAID_FILE "/etc/dhcp/iaid" 50 51 struct iaid_ent { 52 uint32_t ie_iaid; 53 char ie_name[LIFNAMSIZ]; 54 }; 55 56 /* 57 * read_stable_duid(): read the system's stable DUID, if any 58 * 59 * input: size_t *: pointer to a size_t to return the DUID length 60 * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set) 61 * note: memory returned is from malloc; caller must free. 62 */ 63 64 uchar_t * 65 read_stable_duid(size_t *duidlen) 66 { 67 int fd; 68 ssize_t retv; 69 struct stat sb; 70 uchar_t *duid = NULL; 71 72 if ((fd = open(DUID_FILE, O_RDONLY)) == -1) 73 return (NULL); 74 if (fstat(fd, &sb) != -1 && S_ISREG(sb.st_mode) && 75 (duid = malloc(sb.st_size)) != NULL) { 76 retv = read(fd, duid, sb.st_size); 77 if (retv == sb.st_size) { 78 *duidlen = sb.st_size; 79 } else { 80 free(duid); 81 /* 82 * Make sure that errno always gets set when something 83 * goes wrong. 84 */ 85 if (retv >= 0) 86 errno = EINVAL; 87 duid = NULL; 88 } 89 } 90 (void) close(fd); 91 return (duid); 92 } 93 94 /* 95 * write_stable_duid(): write the system's stable DUID. 96 * 97 * input: const uchar_t *: pointer to the DUID buffer 98 * size_t: length of the DUID 99 * output: int: 0 on success, -1 on error. errno is set on error. 100 */ 101 102 int 103 write_stable_duid(const uchar_t *duid, size_t duidlen) 104 { 105 int fd; 106 ssize_t retv; 107 108 (void) unlink(DUID_FILE); 109 if ((fd = open(DUID_FILE, O_WRONLY | O_CREAT, 0644)) == -1) 110 return (-1); 111 retv = write(fd, duid, duidlen); 112 if (retv == duidlen) { 113 return (close(fd)); 114 } else { 115 (void) close(fd); 116 if (retv >= 0) 117 errno = ENOSPC; 118 return (-1); 119 } 120 } 121 122 /* 123 * make_stable_duid(): create a new DUID 124 * 125 * input: const char *: name of physical interface for reference 126 * size_t *: pointer to a size_t to return the DUID length 127 * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set) 128 * note: memory returned is from malloc; caller must free. 129 */ 130 131 uchar_t * 132 make_stable_duid(const char *physintf, size_t *duidlen) 133 { 134 int fd, len; 135 dl_info_ack_t dl_info; 136 dlpi_if_attr_t dia; 137 duid_en_t *den; 138 139 /* 140 * Try to read the MAC layer address for the physical interface 141 * provided as a hint. If that works, we can use a DUID-LLT. 142 */ 143 144 fd = dlpi_if_open(physintf, &dia, B_FALSE); 145 if (fd != -1 && 146 dlpi_info(fd, -1, &dl_info, NULL, NULL, NULL, NULL, NULL, 147 NULL) != -1 && 148 (len = dl_info.dl_addr_length - abs(dl_info.dl_sap_length)) > 0) { 149 duid_llt_t *dllt; 150 uint_t arptype; 151 152 arptype = dlpi_to_arp(dl_info.dl_mac_type); 153 154 if ((dllt = malloc(sizeof (*dllt) + len)) == NULL) { 155 (void) dlpi_close(fd); 156 return (NULL); 157 } 158 if (arptype != 0 && dlpi_phys_addr(fd, -1, DL_CURR_PHYS_ADDR, 159 (uint8_t *)(dllt + 1), NULL) == 0) { 160 time_t now; 161 162 dllt->dllt_dutype = htons(DHCPV6_DUID_LLT); 163 dllt->dllt_hwtype = htons(arptype); 164 now = time(NULL) - DUID_TIME_BASE; 165 dllt->dllt_time = htonl(now); 166 *duidlen = sizeof (*dllt) + len; 167 return ((uchar_t *)dllt); 168 } 169 free(dllt); 170 } 171 if (fd != -1) 172 (void) dlpi_close(fd); 173 174 /* 175 * If we weren't able to create a DUID based on the network interface 176 * in use, then generate one based on a UUID. 177 */ 178 den = malloc(sizeof (*den) + UUID_LEN); 179 if (den != NULL) { 180 uuid_t uuid; 181 182 den->den_dutype = htons(DHCPV6_DUID_EN); 183 DHCPV6_SET_ENTNUM(den, DHCPV6_SUN_ENT); 184 uuid_generate(uuid); 185 (void) memcpy(den + 1, uuid, UUID_LEN); 186 *duidlen = sizeof (*den) + UUID_LEN; 187 } 188 return ((uchar_t *)den); 189 } 190 191 /* 192 * read_stable_iaid(): read a link's stable IAID, if any 193 * 194 * input: const char *: interface name 195 * output: uint32_t: the IAID, or 0 if none 196 */ 197 198 uint32_t 199 read_stable_iaid(const char *intf) 200 { 201 int fd; 202 struct iaid_ent ie; 203 204 if ((fd = open(IAID_FILE, O_RDONLY)) == -1) 205 return (0); 206 while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) { 207 if (strcmp(intf, ie.ie_name) == 0) { 208 (void) close(fd); 209 return (ie.ie_iaid); 210 } 211 } 212 (void) close(fd); 213 return (0); 214 } 215 216 /* 217 * write_stable_iaid(): write out a link's stable IAID 218 * 219 * input: const char *: interface name 220 * output: uint32_t: the IAID, or 0 if none 221 */ 222 223 int 224 write_stable_iaid(const char *intf, uint32_t iaid) 225 { 226 int fd; 227 struct iaid_ent ie; 228 ssize_t retv; 229 230 if ((fd = open(IAID_FILE, O_RDWR | O_CREAT, 0644)) == -1) 231 return (0); 232 while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) { 233 if (strcmp(intf, ie.ie_name) == 0) { 234 (void) close(fd); 235 if (iaid == ie.ie_iaid) { 236 return (0); 237 } else { 238 errno = EINVAL; 239 return (-1); 240 } 241 } 242 } 243 (void) memset(&ie, 0, sizeof (ie)); 244 ie.ie_iaid = iaid; 245 (void) strlcpy(ie.ie_name, intf, sizeof (ie.ie_name)); 246 retv = write(fd, &ie, sizeof (ie)); 247 (void) close(fd); 248 if (retv == sizeof (ie)) { 249 return (0); 250 } else { 251 if (retv >= 0) 252 errno = ENOSPC; 253 return (-1); 254 } 255 } 256 257 /* 258 * make_stable_iaid(): create a stable IAID for a link 259 * 260 * input: const char *: interface name 261 * uint32_t: the ifIndex for this link (as a "hint") 262 * output: uint32_t: the new IAID, never zero 263 */ 264 265 /* ARGSUSED */ 266 uint32_t 267 make_stable_iaid(const char *intf, uint32_t hint) 268 { 269 int fd; 270 struct iaid_ent ie; 271 uint32_t maxid, minunused; 272 boolean_t recheck; 273 274 if ((fd = open(IAID_FILE, O_RDONLY)) == -1) 275 return (hint); 276 maxid = 0; 277 minunused = 1; 278 /* 279 * This logic is deliberately unoptimized. The reason is that it runs 280 * essentially just once per interface for the life of the system. 281 * Once the IAID is established, there's no reason to generate it 282 * again, and all we care about here is correctness. Also, IAIDs tend 283 * to get added in a logical sequence order, so the outer loop should 284 * not normally run more than twice. 285 */ 286 do { 287 recheck = B_FALSE; 288 while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) { 289 if (ie.ie_iaid > maxid) 290 maxid = ie.ie_iaid; 291 if (ie.ie_iaid == minunused) { 292 recheck = B_TRUE; 293 minunused++; 294 } 295 if (ie.ie_iaid == hint) 296 hint = 0; 297 } 298 if (recheck) 299 (void) lseek(fd, 0, SEEK_SET); 300 } while (recheck); 301 (void) close(fd); 302 if (hint != 0) 303 return (hint); 304 else if (maxid != UINT32_MAX) 305 return (maxid + 1); 306 else 307 return (minunused); 308 } 309