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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2019 Joshua M. Clulow <josh@sysmgr.org> 25 */ 26 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <net/if.h> 30 #include <stdlib.h> 31 #include <sys/sockio.h> 32 #include <netinet/in.h> 33 #include <netinet/dhcp.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <search.h> 37 #include <libdevinfo.h> 38 #include <libdlpi.h> 39 #include <netinet/if_ether.h> 40 #include <arpa/inet.h> 41 #include <dhcpmsg.h> 42 43 #include "agent.h" 44 #include "interface.h" 45 #include "util.h" 46 #include "packet.h" 47 #include "states.h" 48 49 dhcp_pif_t *v4root; 50 dhcp_pif_t *v6root; 51 52 static uint_t cached_v4_max_mtu, cached_v6_max_mtu; 53 54 /* 55 * Interface flags to watch: things that should be under our direct control. 56 */ 57 #define DHCP_IFF_WATCH (IFF_DHCPRUNNING | IFF_DEPRECATED | IFF_ADDRCONF | \ 58 IFF_TEMPORARY) 59 60 static void clear_lif_dhcp(dhcp_lif_t *); 61 static void update_pif_mtu(dhcp_pif_t *); 62 63 /* 64 * insert_pif(): creates a new physical interface structure and chains it on 65 * the list. Initializes state that remains consistent across 66 * all use of the physical interface entry. 67 * 68 * input: const char *: the name of the physical interface 69 * boolean_t: if B_TRUE, this is DHCPv6 70 * int *: ignored on input; if insert_pif fails, set to a DHCP_IPC_E_* 71 * error code with the reason why 72 * output: dhcp_pif_t *: a pointer to the new entry, or NULL on failure 73 */ 74 75 dhcp_pif_t * 76 insert_pif(const char *pname, boolean_t isv6, int *error) 77 { 78 dhcp_pif_t *pif; 79 struct lifreq lifr; 80 lifgroupinfo_t lifgr; 81 dlpi_handle_t dh = NULL; 82 int fd = isv6 ? v6_sock_fd : v4_sock_fd; 83 84 if ((pif = calloc(1, sizeof (*pif))) == NULL) { 85 dhcpmsg(MSG_ERR, "insert_pif: cannot allocate pif entry for " 86 "%s", pname); 87 *error = DHCP_IPC_E_MEMORY; 88 return (NULL); 89 } 90 91 pif->pif_isv6 = isv6; 92 pif->pif_hold_count = 1; 93 pif->pif_running = B_TRUE; 94 95 if (strlcpy(pif->pif_name, pname, LIFNAMSIZ) >= LIFNAMSIZ) { 96 dhcpmsg(MSG_ERROR, "insert_pif: interface name %s is too long", 97 pname); 98 *error = DHCP_IPC_E_INVIF; 99 goto failure; 100 } 101 102 /* 103 * This is a bit gross, but IP has a confused interface. We must 104 * assume that the zeroth LIF is plumbed, and must query there to get 105 * the interface index number. 106 */ 107 (void) strlcpy(lifr.lifr_name, pname, LIFNAMSIZ); 108 109 if (ioctl(fd, SIOCGLIFINDEX, &lifr) == -1) { 110 *error = (errno == ENXIO) ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT; 111 dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFINDEX for %s", pname); 112 goto failure; 113 } 114 pif->pif_index = lifr.lifr_index; 115 116 /* 117 * Check if this is a VRRP interface. If yes, its IP addresses (the 118 * VRRP virtual addresses) cannot be configured using DHCP. 119 */ 120 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 121 *error = (errno == ENXIO) ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT; 122 dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFFLAGS for %s", pname); 123 goto failure; 124 } 125 126 if (lifr.lifr_flags & IFF_VRRP) { 127 *error = DHCP_IPC_E_INVIF; 128 dhcpmsg(MSG_ERROR, "insert_pif: VRRP virtual addresses over %s " 129 "cannot be configured using DHCP", pname); 130 goto failure; 131 } 132 133 if (ioctl(fd, SIOCGLIFMTU, &lifr) == -1) { 134 *error = (errno == ENXIO) ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT; 135 dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFMTU for %s", pname); 136 goto failure; 137 } 138 pif->pif_mtu_orig = pif->pif_mtu = lifr.lifr_mtu; 139 dhcpmsg(MSG_DEBUG, "insert_pif: original MTU of %s is %u", pname, 140 pif->pif_mtu_orig); 141 142 if (pif->pif_mtu < DHCP_DEF_MAX_SIZE) { 143 dhcpmsg(MSG_ERROR, "insert_pif: MTU of %s is too small to " 144 "support DHCP (%u < %u)", pname, pif->pif_mtu, 145 DHCP_DEF_MAX_SIZE); 146 *error = DHCP_IPC_E_INVIF; 147 goto failure; 148 } 149 150 /* 151 * Check if the pif is in an IPMP group. Interfaces using IPMP don't 152 * have dedicated hardware addresses, and get their hardware type from 153 * the SIOCGLIFGROUPINFO ioctl rather than DLPI. 154 */ 155 if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) == -1) { 156 *error = DHCP_IPC_E_INT; 157 dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFGROUPNAME for %s", pname); 158 goto failure; 159 } 160 161 if (lifr.lifr_groupname[0] != '\0') { 162 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, 163 LIFGRNAMSIZ); 164 if (ioctl(fd, SIOCGLIFGROUPINFO, &lifgr) == -1) { 165 *error = DHCP_IPC_E_INT; 166 dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFGROUPINFO for %s", 167 lifgr.gi_grname); 168 goto failure; 169 } 170 171 pif->pif_hwtype = dlpi_arptype(lifgr.gi_mactype); 172 pif->pif_under_ipmp = (strcmp(pname, lifgr.gi_grifname) != 0); 173 (void) strlcpy(pif->pif_grifname, lifgr.gi_grifname, LIFNAMSIZ); 174 175 /* 176 * For IPMP underlying interfaces, stash the interface index 177 * of the IPMP meta-interface; we'll use it to send/receive 178 * traffic. This is both necessary (since IP_BOUND_IF for 179 * non-unicast traffic won't work on underlying interfaces) 180 * and preferred (since a test address lease will be able to 181 * be maintained as long as another interface in the group is 182 * still functioning). 183 */ 184 if (pif->pif_under_ipmp) { 185 (void) strlcpy(lifr.lifr_name, pif->pif_grifname, 186 LIFNAMSIZ); 187 188 if (ioctl(fd, SIOCGLIFINDEX, &lifr) == -1) { 189 *error = DHCP_IPC_E_INT; 190 dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFINDEX " 191 "for %s", lifr.lifr_name); 192 goto failure; 193 } 194 pif->pif_grindex = lifr.lifr_index; 195 } 196 } 197 198 /* 199 * For IPv4, if the hardware type is still unknown, use DLPI to 200 * determine it, the hardware address, and hardware address length. 201 */ 202 if (!isv6 && pif->pif_hwtype == 0) { 203 int rc; 204 dlpi_info_t dlinfo; 205 206 if ((rc = dlpi_open(pname, &dh, 0)) != DLPI_SUCCESS) { 207 dhcpmsg(MSG_ERROR, "insert_pif: dlpi_open: %s", 208 dlpi_strerror(rc)); 209 *error = DHCP_IPC_E_INVIF; 210 goto failure; 211 } 212 213 if ((rc = dlpi_bind(dh, ETHERTYPE_IP, NULL)) != DLPI_SUCCESS) { 214 dhcpmsg(MSG_ERROR, "insert_pif: dlpi_bind: %s", 215 dlpi_strerror(rc)); 216 *error = DHCP_IPC_E_INVIF; 217 goto failure; 218 } 219 220 if ((rc = dlpi_info(dh, &dlinfo, 0)) != DLPI_SUCCESS) { 221 dhcpmsg(MSG_ERROR, "insert_pif: dlpi_info: %s", 222 dlpi_strerror(rc)); 223 *error = DHCP_IPC_E_INVIF; 224 goto failure; 225 } 226 227 pif->pif_hwtype = dlpi_arptype(dlinfo.di_mactype); 228 pif->pif_hwlen = dlinfo.di_physaddrlen; 229 230 dhcpmsg(MSG_DEBUG, "insert_pif: %s: hwtype %d, hwlen %d", 231 pname, pif->pif_hwtype, pif->pif_hwlen); 232 233 if (pif->pif_hwlen > 0) { 234 pif->pif_hwaddr = malloc(pif->pif_hwlen); 235 if (pif->pif_hwaddr == NULL) { 236 dhcpmsg(MSG_ERR, "insert_pif: cannot allocate " 237 "pif_hwaddr for %s", pname); 238 *error = DHCP_IPC_E_MEMORY; 239 goto failure; 240 } 241 (void) memcpy(pif->pif_hwaddr, dlinfo.di_physaddr, 242 pif->pif_hwlen); 243 } 244 245 dlpi_close(dh); 246 dh = NULL; 247 } 248 249 insque(pif, isv6 ? &v6root : &v4root); 250 251 return (pif); 252 failure: 253 if (dh != NULL) 254 dlpi_close(dh); 255 release_pif(pif); 256 return (NULL); 257 } 258 259 /* 260 * hold_pif(): acquire a hold on a physical interface structure. 261 * 262 * input: dhcp_pif_t *: a pointer to the PIF structure 263 * output: none 264 */ 265 266 void 267 hold_pif(dhcp_pif_t *pif) 268 { 269 pif->pif_hold_count++; 270 dhcpmsg(MSG_DEBUG2, "hold_pif: hold count on %s: %u", pif->pif_name, 271 pif->pif_hold_count); 272 } 273 274 /* 275 * release_pif(): release a hold on a physical interface structure; will 276 * destroy the structure on the last hold removed. 277 * 278 * input: dhcp_pif_t *: a pointer to the PIF structure 279 * output: none 280 */ 281 282 void 283 release_pif(dhcp_pif_t *pif) 284 { 285 if (pif->pif_hold_count == 0) { 286 dhcpmsg(MSG_CRIT, "release_pif: extraneous release"); 287 return; 288 } 289 290 if (--pif->pif_hold_count == 0) { 291 dhcpmsg(MSG_DEBUG, "release_pif: freeing PIF %s", 292 pif->pif_name); 293 294 /* 295 * Unplumbing the last logical interface on top of this 296 * physical interface should have returned the MTU to its 297 * original value. 298 */ 299 update_pif_mtu(pif); 300 if (pif->pif_mtu != pif->pif_mtu_orig) { 301 dhcpmsg(MSG_CRIT, "release_pif: PIF %s MTU is %u, " 302 "expected %u", pif->pif_name, pif->pif_mtu, 303 pif->pif_mtu_orig); 304 } 305 306 remque(pif); 307 free(pif->pif_hwaddr); 308 free(pif); 309 } else { 310 dhcpmsg(MSG_DEBUG2, "release_pif: hold count on %s: %u", 311 pif->pif_name, pif->pif_hold_count); 312 } 313 } 314 315 /* 316 * lookup_pif_by_uindex(): Looks up PIF entries given truncated index and 317 * previous PIF pointer (or NULL for list start). 318 * Caller is expected to iterate through all 319 * potential matches to find interface of interest. 320 * 321 * input: uint16_t: the interface index (truncated) 322 * dhcp_pif_t *: the previous PIF, or NULL for list start 323 * boolean_t: B_TRUE if using DHCPv6, B_FALSE otherwise 324 * output: dhcp_pif_t *: the next matching PIF, or NULL if not found 325 * note: This operates using the 'truncated' (16-bit) ifindex as seen by 326 * routing socket clients. The value stored in pif_index is the 327 * 32-bit ifindex from the ioctl interface. 328 */ 329 330 dhcp_pif_t * 331 lookup_pif_by_uindex(uint16_t ifindex, dhcp_pif_t *pif, boolean_t isv6) 332 { 333 if (pif == NULL) 334 pif = isv6 ? v6root : v4root; 335 else 336 pif = pif->pif_next; 337 338 for (; pif != NULL; pif = pif->pif_next) { 339 if ((pif->pif_index & 0xffff) == ifindex) 340 break; 341 } 342 343 return (pif); 344 } 345 346 /* 347 * lookup_pif_by_name(): Looks up a physical interface entry given a name. 348 * 349 * input: const char *: the physical interface name 350 * boolean_t: B_TRUE if using DHCPv6, B_FALSE otherwise 351 * output: dhcp_pif_t *: the matching PIF, or NULL if not found 352 */ 353 354 dhcp_pif_t * 355 lookup_pif_by_name(const char *pname, boolean_t isv6) 356 { 357 dhcp_pif_t *pif; 358 359 pif = isv6 ? v6root : v4root; 360 361 for (; pif != NULL; pif = pif->pif_next) { 362 if (strcmp(pif->pif_name, pname) == 0) 363 break; 364 } 365 366 return (pif); 367 } 368 369 /* 370 * pif_status(): update the physical interface up/down status. 371 * 372 * input: dhcp_pif_t *: the physical interface to be updated 373 * boolean_t: B_TRUE if the interface is going up 374 * output: none 375 */ 376 377 void 378 pif_status(dhcp_pif_t *pif, boolean_t isup) 379 { 380 dhcp_lif_t *lif; 381 dhcp_smach_t *dsmp; 382 383 pif->pif_running = isup; 384 dhcpmsg(MSG_DEBUG, "interface %s has %s", pif->pif_name, 385 isup ? "come back up" : "gone down"); 386 for (lif = pif->pif_lifs; lif != NULL; lif = lif->lif_next) { 387 for (dsmp = lif->lif_smachs; dsmp != NULL; 388 dsmp = dsmp->dsm_next) { 389 if (isup) 390 refresh_smach(dsmp); 391 else 392 remove_default_routes(dsmp); 393 } 394 } 395 } 396 397 /* Helper for insert_lif: extract addresses as defined */ 398 #define ASSIGN_ADDR(v4, v6, lf) \ 399 if (pif->pif_isv6) { \ 400 lif->v6 = ((struct sockaddr_in6 *)&lifr.lf)->sin6_addr; \ 401 } else { \ 402 lif->v4 = ((struct sockaddr_in *)&lifr.lf)->sin_addr.s_addr; \ 403 } 404 405 /* 406 * insert_lif(): Creates a new logical interface structure and chains it on 407 * the list for a given physical interface. Initializes state 408 * that remains consistent across all use of the logical 409 * interface entry. Caller's PIF hold is transferred to the 410 * LIF on success, and is dropped on failure. 411 * 412 * input: dhcp_pif_t *: pointer to the physical interface for this LIF 413 * const char *: the name of the logical interface 414 * int *: ignored on input; if insert_pif fails, set to a DHCP_IPC_E_* 415 * error code with the reason why 416 * output: dhcp_lif_t *: a pointer to the new entry, or NULL on failure 417 */ 418 419 dhcp_lif_t * 420 insert_lif(dhcp_pif_t *pif, const char *lname, int *error) 421 { 422 dhcp_lif_t *lif; 423 int fd; 424 struct lifreq lifr; 425 426 if ((lif = calloc(1, sizeof (*lif))) == NULL) { 427 dhcpmsg(MSG_ERR, "insert_lif: cannot allocate lif entry for " 428 "%s", lname); 429 *error = DHCP_IPC_E_MEMORY; 430 return (NULL); 431 } 432 433 lif->lif_sock_ip_fd = -1; 434 lif->lif_packet_id = -1; 435 lif->lif_iaid_id = -1; 436 lif->lif_hold_count = 1; 437 lif->lif_pif = pif; 438 lif->lif_removed = B_TRUE; 439 init_timer(&lif->lif_preferred, 0); 440 init_timer(&lif->lif_expire, 0); 441 442 if (strlcpy(lif->lif_name, lname, LIFNAMSIZ) >= LIFNAMSIZ) { 443 dhcpmsg(MSG_ERROR, "insert_lif: interface name %s is too long", 444 lname); 445 *error = DHCP_IPC_E_INVIF; 446 goto failure; 447 } 448 449 (void) strlcpy(lifr.lifr_name, lname, LIFNAMSIZ); 450 451 fd = pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 452 453 if (ioctl(fd, SIOCGLIFADDR, &lifr) == -1) { 454 if (errno == ENXIO) 455 *error = DHCP_IPC_E_INVIF; 456 else 457 *error = DHCP_IPC_E_INT; 458 dhcpmsg(MSG_ERR, "insert_lif: SIOCGLIFADDR for %s", lname); 459 goto failure; 460 } 461 ASSIGN_ADDR(lif_addr, lif_v6addr, lifr_addr); 462 463 if (ioctl(fd, SIOCGLIFNETMASK, &lifr) == -1) { 464 if (errno == ENXIO) 465 *error = DHCP_IPC_E_INVIF; 466 else 467 *error = DHCP_IPC_E_INT; 468 dhcpmsg(MSG_ERR, "insert_lif: SIOCGLIFNETMASK for %s", lname); 469 goto failure; 470 } 471 ASSIGN_ADDR(lif_netmask, lif_v6mask, lifr_addr); 472 473 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 474 *error = DHCP_IPC_E_INT; 475 dhcpmsg(MSG_ERR, "insert_lif: SIOCGLIFFLAGS for %s", lname); 476 goto failure; 477 } 478 lif->lif_flags = lifr.lifr_flags; 479 480 /* 481 * If we've just detected the interface going up or down, then signal 482 * an appropriate action. There may be other state machines here. 483 */ 484 if ((lifr.lifr_flags & IFF_RUNNING) && !pif->pif_running) { 485 pif_status(pif, B_TRUE); 486 } else if (!(lifr.lifr_flags & IFF_RUNNING) && pif->pif_running) { 487 pif_status(pif, B_FALSE); 488 } 489 490 if (lifr.lifr_flags & IFF_POINTOPOINT) { 491 if (ioctl(fd, SIOCGLIFDSTADDR, &lifr) == -1) { 492 *error = DHCP_IPC_E_INT; 493 dhcpmsg(MSG_ERR, "insert_lif: SIOCGLIFDSTADDR for %s", 494 lname); 495 goto failure; 496 } 497 ASSIGN_ADDR(lif_peer, lif_v6peer, lifr_dstaddr); 498 } else if (!pif->pif_isv6 && (lifr.lifr_flags & IFF_BROADCAST)) { 499 if (ioctl(fd, SIOCGLIFBRDADDR, &lifr) == -1) { 500 *error = DHCP_IPC_E_INT; 501 dhcpmsg(MSG_ERR, "insert_lif: SIOCGLIFBRDADDR for %s", 502 lname); 503 goto failure; 504 } 505 lif->lif_broadcast = 506 ((struct sockaddr_in *)&lifr.lifr_broadaddr)->sin_addr. 507 s_addr; 508 } 509 510 if (pif->pif_isv6) 511 cached_v6_max_mtu = 0; 512 else 513 cached_v4_max_mtu = 0; 514 515 lif->lif_removed = B_FALSE; 516 insque(lif, &pif->pif_lifs); 517 518 return (lif); 519 520 failure: 521 release_lif(lif); 522 return (NULL); 523 } 524 525 /* 526 * hold_lif(): acquire a hold on a logical interface structure. 527 * 528 * input: dhcp_lif_t *: a pointer to the LIF structure 529 * output: none 530 */ 531 532 void 533 hold_lif(dhcp_lif_t *lif) 534 { 535 lif->lif_hold_count++; 536 dhcpmsg(MSG_DEBUG2, "hold_lif: hold count on %s: %u", lif->lif_name, 537 lif->lif_hold_count); 538 } 539 540 /* 541 * release_lif(): release a hold on a logical interface structure; will 542 * destroy the structure on the last hold removed. 543 * 544 * input: dhcp_lif_t *: a pointer to the LIF structure 545 * output: none 546 */ 547 548 void 549 release_lif(dhcp_lif_t *lif) 550 { 551 if (lif->lif_hold_count == 0) { 552 dhcpmsg(MSG_CRIT, "release_lif: extraneous release on %s", 553 lif->lif_name); 554 return; 555 } 556 557 if (lif->lif_hold_count == 1 && !lif->lif_removed) { 558 unplumb_lif(lif); 559 return; 560 } 561 562 if (--lif->lif_hold_count == 0) { 563 dhcp_pif_t *pif; 564 565 dhcpmsg(MSG_DEBUG, "release_lif: freeing LIF %s", 566 lif->lif_name); 567 568 if (lif->lif_lease != NULL) 569 dhcpmsg(MSG_CRIT, 570 "release_lif: still holding lease at last hold!"); 571 close_ip_lif(lif); 572 pif = lif->lif_pif; 573 if (pif->pif_isv6) 574 cached_v6_max_mtu = 0; 575 else 576 cached_v4_max_mtu = 0; 577 release_pif(pif); 578 free(lif); 579 } else { 580 dhcpmsg(MSG_DEBUG2, "release_lif: hold count on %s: %u", 581 lif->lif_name, lif->lif_hold_count); 582 } 583 } 584 585 /* 586 * remove_lif(): remove a logical interface from its PIF and lease (if any) and 587 * the lease's hold on the LIF. Assumes that we did not plumb 588 * the interface. 589 * 590 * input: dhcp_lif_t *: a pointer to the LIF structure 591 * output: none 592 */ 593 594 void 595 remove_lif(dhcp_lif_t *lif) 596 { 597 if (lif->lif_plumbed) { 598 dhcpmsg(MSG_CRIT, "remove_lif: attempted invalid removal of %s", 599 lif->lif_name); 600 return; 601 } 602 if (lif->lif_removed) { 603 dhcpmsg(MSG_CRIT, "remove_lif: extraneous removal of %s", 604 lif->lif_name); 605 } else { 606 dhcp_lif_t *lifnext; 607 dhcp_lease_t *dlp; 608 609 dhcpmsg(MSG_DEBUG2, "remove_lif: removing %s", lif->lif_name); 610 lif->lif_removed = B_TRUE; 611 lifnext = lif->lif_next; 612 clear_lif_dhcp(lif); 613 cancel_lif_timers(lif); 614 if (lif->lif_iaid_id != -1 && 615 iu_cancel_timer(tq, lif->lif_iaid_id, NULL) == 1) { 616 lif->lif_iaid_id = -1; 617 release_lif(lif); 618 } 619 620 /* Remove from PIF list */ 621 remque(lif); 622 623 /* If we were part of a lease, then remove ourselves */ 624 if ((dlp = lif->lif_lease) != NULL) { 625 if (--dlp->dl_nlifs == 0) 626 dlp->dl_lifs = NULL; 627 else if (dlp->dl_lifs == lif) 628 dlp->dl_lifs = lifnext; 629 if (lif->lif_declined != NULL) { 630 dlp->dl_smach->dsm_lif_down--; 631 lif->lif_declined = NULL; 632 } 633 if (lif->lif_dad_wait) { 634 lif->lif_dad_wait = _B_FALSE; 635 dlp->dl_smach->dsm_lif_wait--; 636 } 637 lif->lif_lease = NULL; 638 release_lif(lif); 639 } 640 } 641 } 642 643 /* 644 * lookup_lif_by_name(): Looks up a logical interface entry given a name and 645 * a physical interface. 646 * 647 * input: const char *: the logical interface name 648 * const dhcp_pif_t *: the physical interface 649 * output: dhcp_lif_t *: the matching LIF, or NULL if not found 650 */ 651 652 dhcp_lif_t * 653 lookup_lif_by_name(const char *lname, const dhcp_pif_t *pif) 654 { 655 dhcp_lif_t *lif; 656 657 for (lif = pif->pif_lifs; lif != NULL; lif = lif->lif_next) { 658 if (strcmp(lif->lif_name, lname) == 0) 659 break; 660 } 661 662 return (lif); 663 } 664 665 /* 666 * checkaddr(): checks if the given address is still set on the given LIF 667 * 668 * input: const dhcp_lif_t *: the LIF to check 669 * int: the address to look up on the interface (ioctl) 670 * const in6_addr_t *: the address to compare to 671 * const char *: name of the address for logging purposes 672 * output: boolean_t: B_TRUE if the address is still set; B_FALSE if not 673 */ 674 675 static boolean_t 676 checkaddr(const dhcp_lif_t *lif, int ioccmd, const in6_addr_t *addr, 677 const char *aname) 678 { 679 boolean_t isv6; 680 int fd; 681 struct lifreq lifr; 682 char abuf1[INET6_ADDRSTRLEN]; 683 char abuf2[INET6_ADDRSTRLEN]; 684 685 (void) memset(&lifr, 0, sizeof (struct lifreq)); 686 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 687 688 isv6 = lif->lif_pif->pif_isv6; 689 fd = isv6 ? v6_sock_fd : v4_sock_fd; 690 691 if (ioctl(fd, ioccmd, &lifr) == -1) { 692 if (errno == ENXIO) { 693 dhcpmsg(MSG_WARNING, "checkaddr: interface %s is gone", 694 lif->lif_name); 695 return (B_FALSE); 696 } 697 dhcpmsg(MSG_DEBUG, 698 "checkaddr: ignoring ioctl error on %s %x: %s", 699 lif->lif_name, ioccmd, strerror(errno)); 700 } else if (isv6) { 701 struct sockaddr_in6 *sin6 = 702 (struct sockaddr_in6 *)&lifr.lifr_addr; 703 704 if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, addr)) { 705 dhcpmsg(MSG_WARNING, 706 "checkaddr: expected %s %s on %s, have %s", aname, 707 inet_ntop(AF_INET6, addr, abuf1, sizeof (abuf1)), 708 lif->lif_name, inet_ntop(AF_INET6, &sin6->sin6_addr, 709 abuf2, sizeof (abuf2))); 710 return (B_FALSE); 711 } 712 } else { 713 struct sockaddr_in *sinp = 714 (struct sockaddr_in *)&lifr.lifr_addr; 715 ipaddr_t v4addr; 716 717 IN6_V4MAPPED_TO_IPADDR(addr, v4addr); 718 if (sinp->sin_addr.s_addr != v4addr) { 719 dhcpmsg(MSG_WARNING, 720 "checkaddr: expected %s %s on %s, have %s", aname, 721 inet_ntop(AF_INET, &v4addr, abuf1, sizeof (abuf1)), 722 lif->lif_name, inet_ntop(AF_INET, &sinp->sin_addr, 723 abuf2, sizeof (abuf2))); 724 return (B_FALSE); 725 } 726 } 727 return (B_TRUE); 728 } 729 730 /* 731 * verify_lif(): verifies than a LIF is still valid (i.e., has not been 732 * explicitly or implicitly dropped or released) 733 * 734 * input: const dhcp_lif_t *: the LIF to verify 735 * output: boolean_t: B_TRUE if the LIF is still valid, B_FALSE otherwise 736 */ 737 738 boolean_t 739 verify_lif(const dhcp_lif_t *lif) 740 { 741 boolean_t isv6; 742 int fd; 743 struct lifreq lifr; 744 dhcp_pif_t *pif = lif->lif_pif; 745 746 (void) memset(&lifr, 0, sizeof (struct lifreq)); 747 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 748 749 isv6 = pif->pif_isv6; 750 fd = isv6 ? v6_sock_fd : v4_sock_fd; 751 752 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 753 if (errno != ENXIO) { 754 dhcpmsg(MSG_ERR, 755 "verify_lif: SIOCGLIFFLAGS failed on %s", 756 lif->lif_name); 757 } 758 return (B_FALSE); 759 } 760 761 /* 762 * If important flags have changed, then abandon the interface. 763 */ 764 if ((lif->lif_flags ^ lifr.lifr_flags) & DHCP_IFF_WATCH) { 765 dhcpmsg(MSG_DEBUG, "verify_lif: unexpected flag change on %s: " 766 "%llx to %llx (%llx)", lif->lif_name, lif->lif_flags, 767 lifr.lifr_flags, (lif->lif_flags ^ lifr.lifr_flags) & 768 DHCP_IFF_WATCH); 769 return (B_FALSE); 770 } 771 772 /* 773 * Check for delete and recreate. 774 */ 775 if (ioctl(fd, SIOCGLIFINDEX, &lifr) == -1) { 776 if (errno != ENXIO) { 777 dhcpmsg(MSG_ERR, "verify_lif: SIOCGLIFINDEX failed " 778 "on %s", lif->lif_name); 779 } 780 return (B_FALSE); 781 } 782 if (lifr.lifr_index != pif->pif_index) { 783 dhcpmsg(MSG_DEBUG, 784 "verify_lif: ifindex on %s changed: %u to %u", 785 lif->lif_name, pif->pif_index, lifr.lifr_index); 786 return (B_FALSE); 787 } 788 789 if (pif->pif_under_ipmp) { 790 (void) strlcpy(lifr.lifr_name, pif->pif_grifname, LIFNAMSIZ); 791 792 if (ioctl(fd, SIOCGLIFINDEX, &lifr) == -1) { 793 if (errno != ENXIO) { 794 dhcpmsg(MSG_ERR, "verify_lif: SIOCGLIFINDEX " 795 "failed on %s", lifr.lifr_name); 796 } 797 return (B_FALSE); 798 } 799 800 if (lifr.lifr_index != pif->pif_grindex) { 801 dhcpmsg(MSG_DEBUG, "verify_lif: IPMP group ifindex " 802 "on %s changed: %u to %u", lifr.lifr_name, 803 pif->pif_grindex, lifr.lifr_index); 804 return (B_FALSE); 805 } 806 } 807 808 /* 809 * If the IP address, netmask, or broadcast address have changed, or 810 * the interface has been unplumbed, then we act like there has been an 811 * implicit drop. (Note that the netmask is under DHCP control for 812 * IPv4, but not for DHCPv6, and that IPv6 doesn't have broadcast 813 * addresses.) 814 */ 815 816 if (!checkaddr(lif, SIOCGLIFADDR, &lif->lif_v6addr, "local address")) 817 return (B_FALSE); 818 819 if (isv6) { 820 /* 821 * If it's not point-to-point, we're done. If it is, then 822 * check the peer's address as well. 823 */ 824 return (!(lif->lif_flags & IFF_POINTOPOINT) || 825 checkaddr(lif, SIOCGLIFDSTADDR, &lif->lif_v6peer, 826 "peer address")); 827 } else { 828 if (!checkaddr(lif, SIOCGLIFNETMASK, &lif->lif_v6mask, 829 "netmask")) 830 return (B_FALSE); 831 832 return (checkaddr(lif, 833 (lif->lif_flags & IFF_POINTOPOINT) ? SIOCGLIFDSTADDR : 834 SIOCGLIFBRDADDR, &lif->lif_v6peer, "peer address")); 835 } 836 } 837 838 /* 839 * canonize_lif(): puts the interface in a canonical (zeroed) form. This is 840 * used only on the "main" LIF for IPv4. All other interfaces 841 * are under dhcpagent control and are removed using 842 * unplumb_lif(). 843 * 844 * input: dhcp_lif_t *: the interface to canonize 845 * boolean_t: only canonize lif if it's under DHCP control 846 * output: none 847 */ 848 849 static void 850 canonize_lif(dhcp_lif_t *lif, boolean_t dhcponly) 851 { 852 boolean_t isv6; 853 int fd; 854 struct lifreq lifr; 855 856 /* 857 * If there's nothing here, then don't touch the interface. This can 858 * happen when an already-canonized LIF is recanonized. 859 */ 860 if (IN6_IS_ADDR_UNSPECIFIED(&lif->lif_v6addr)) 861 return; 862 863 isv6 = lif->lif_pif->pif_isv6; 864 dhcpmsg(MSG_VERBOSE, "canonizing IPv%d interface %s", 865 isv6 ? 6 : 4, lif->lif_name); 866 867 lif->lif_v6addr = my_in6addr_any; 868 lif->lif_v6mask = my_in6addr_any; 869 lif->lif_v6peer = my_in6addr_any; 870 871 (void) memset(&lifr, 0, sizeof (struct lifreq)); 872 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 873 874 fd = isv6 ? v6_sock_fd : v4_sock_fd; 875 876 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 877 if (errno != ENXIO) { 878 dhcpmsg(MSG_ERR, "canonize_lif: can't get flags for %s", 879 lif->lif_name); 880 } 881 return; 882 } 883 lif->lif_flags = lifr.lifr_flags; 884 885 if (dhcponly && !(lifr.lifr_flags & IFF_DHCPRUNNING)) { 886 dhcpmsg(MSG_INFO, 887 "canonize_lif: cannot clear %s; flags are %llx", 888 lif->lif_name, lifr.lifr_flags); 889 return; 890 } 891 892 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 893 if (isv6) { 894 struct sockaddr_in6 *sin6 = 895 (struct sockaddr_in6 *)&lifr.lifr_addr; 896 897 sin6->sin6_family = AF_INET6; 898 sin6->sin6_addr = my_in6addr_any; 899 } else { 900 struct sockaddr_in *sinv = 901 (struct sockaddr_in *)&lifr.lifr_addr; 902 903 sinv->sin_family = AF_INET; 904 sinv->sin_addr.s_addr = htonl(INADDR_ANY); 905 } 906 907 if (ioctl(fd, SIOCSLIFADDR, &lifr) == -1) { 908 dhcpmsg(MSG_ERR, 909 "canonize_lif: can't clear local address on %s", 910 lif->lif_name); 911 } 912 913 /* Clearing the address means that we're no longer waiting on DAD */ 914 if (lif->lif_dad_wait) { 915 lif->lif_dad_wait = _B_FALSE; 916 lif->lif_lease->dl_smach->dsm_lif_wait--; 917 } 918 919 if (lif->lif_flags & IFF_POINTOPOINT) { 920 if (ioctl(fd, SIOCSLIFDSTADDR, &lifr) == -1) { 921 dhcpmsg(MSG_ERR, 922 "canonize_lif: can't clear remote address on %s", 923 lif->lif_name); 924 } 925 } else if (!isv6) { 926 if (ioctl(fd, SIOCSLIFBRDADDR, &lifr) == -1) { 927 dhcpmsg(MSG_ERR, 928 "canonize_lif: can't clear broadcast address on %s", 929 lif->lif_name); 930 } 931 } 932 933 /* 934 * Clear the netmask last as it has to be refetched after clearing. 935 * Netmask is under in.ndpd control with IPv6. 936 */ 937 if (!isv6) { 938 /* Clear the netmask */ 939 if (ioctl(fd, SIOCSLIFNETMASK, &lifr) == -1) { 940 dhcpmsg(MSG_ERR, 941 "canonize_lif: can't clear netmask on %s", 942 lif->lif_name); 943 } else { 944 /* 945 * When the netmask is cleared, the kernel actually sets 946 * the netmask to 255.0.0.0. So, refetch that netmask. 947 */ 948 if (ioctl(fd, SIOCGLIFNETMASK, &lifr) == -1) { 949 dhcpmsg(MSG_ERR, 950 "canonize_lif: can't reload cleared " 951 "netmask on %s", lif->lif_name); 952 } else { 953 /* Refetch succeeded, update LIF */ 954 lif->lif_netmask = 955 ((struct sockaddr_in *)&lifr.lifr_addr)-> 956 sin_addr.s_addr; 957 } 958 } 959 } 960 } 961 962 /* 963 * plumb_lif(): Adds the LIF to the system. This is used for all 964 * DHCPv6-derived interfaces. The returned LIF has a hold 965 * on it. The caller (configure_v6_leases) deals with the DAD 966 * wait counters. 967 * 968 * input: dhcp_lif_t *: the interface to unplumb 969 * output: none 970 */ 971 972 dhcp_lif_t * 973 plumb_lif(dhcp_pif_t *pif, const in6_addr_t *addr) 974 { 975 dhcp_lif_t *lif; 976 char abuf[INET6_ADDRSTRLEN]; 977 struct lifreq lifr; 978 struct sockaddr_in6 *sin6; 979 int error; 980 981 (void) inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)); 982 983 for (lif = pif->pif_lifs; lif != NULL; lif = lif->lif_next) { 984 if (IN6_ARE_ADDR_EQUAL(&lif->lif_v6addr, addr)) { 985 dhcpmsg(MSG_ERR, 986 "plumb_lif: entry for %s already exists!", abuf); 987 return (NULL); 988 } 989 } 990 991 /* First, create a new zero-address logical interface */ 992 (void) memset(&lifr, 0, sizeof (lifr)); 993 (void) strlcpy(lifr.lifr_name, pif->pif_name, sizeof (lifr.lifr_name)); 994 if (ioctl(v6_sock_fd, SIOCLIFADDIF, &lifr) == -1) { 995 dhcpmsg(MSG_ERR, "plumb_lif: SIOCLIFADDIF %s", pif->pif_name); 996 return (NULL); 997 } 998 999 /* Next, set the netmask to all ones */ 1000 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1001 sin6->sin6_family = AF_INET6; 1002 (void) memset(&sin6->sin6_addr, 0xff, sizeof (sin6->sin6_addr)); 1003 if (ioctl(v6_sock_fd, SIOCSLIFNETMASK, &lifr) == -1) { 1004 dhcpmsg(MSG_ERR, "plumb_lif: SIOCSLIFNETMASK %s", 1005 lifr.lifr_name); 1006 goto failure; 1007 } 1008 1009 /* Now set the interface address */ 1010 sin6->sin6_addr = *addr; 1011 if (ioctl(v6_sock_fd, SIOCSLIFADDR, &lifr) == -1) { 1012 dhcpmsg(MSG_ERR, "plumb_lif: SIOCSLIFADDR %s %s", 1013 lifr.lifr_name, abuf); 1014 goto failure; 1015 } 1016 1017 /* Mark the interface up */ 1018 if (ioctl(v6_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { 1019 dhcpmsg(MSG_ERR, "plumb_lif: SIOCGLIFFLAGS %s", 1020 lifr.lifr_name); 1021 goto failure; 1022 } 1023 1024 /* 1025 * See comment in set_lif_dhcp(). 1026 */ 1027 if (pif->pif_under_ipmp && !(lifr.lifr_flags & IFF_NOFAILOVER)) 1028 lifr.lifr_flags |= IFF_NOFAILOVER | IFF_DEPRECATED; 1029 1030 lifr.lifr_flags |= IFF_UP | IFF_DHCPRUNNING; 1031 if (ioctl(v6_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1032 dhcpmsg(MSG_ERR, "plumb_lif: SIOCSLIFFLAGS %s", 1033 lifr.lifr_name); 1034 goto failure; 1035 } 1036 1037 /* Now we can create the internal LIF structure */ 1038 hold_pif(pif); 1039 if ((lif = insert_lif(pif, lifr.lifr_name, &error)) == NULL) 1040 goto failure; 1041 1042 dhcpmsg(MSG_DEBUG, "plumb_lif: plumbed up %s on %s", abuf, 1043 lif->lif_name); 1044 lif->lif_plumbed = B_TRUE; 1045 1046 return (lif); 1047 1048 failure: 1049 if (ioctl(v6_sock_fd, SIOCLIFREMOVEIF, &lifr) == -1 && 1050 errno != ENXIO) { 1051 dhcpmsg(MSG_ERR, "plumb_lif: SIOCLIFREMOVEIF %s", 1052 lifr.lifr_name); 1053 } 1054 return (NULL); 1055 } 1056 1057 /* 1058 * unplumb_lif(): Removes the LIF from dhcpagent and the system. This is used 1059 * for all interfaces configured by DHCP (those in leases). 1060 * 1061 * input: dhcp_lif_t *: the interface to unplumb 1062 * output: none 1063 */ 1064 1065 void 1066 unplumb_lif(dhcp_lif_t *lif) 1067 { 1068 dhcp_lease_t *dlp; 1069 1070 /* 1071 * If we adjusted the MTU for this interface, put it back now: 1072 */ 1073 clear_lif_mtu(lif); 1074 1075 if (lif->lif_plumbed) { 1076 struct lifreq lifr; 1077 1078 (void) memset(&lifr, 0, sizeof (lifr)); 1079 (void) strlcpy(lifr.lifr_name, lif->lif_name, 1080 sizeof (lifr.lifr_name)); 1081 1082 if (ioctl(v6_sock_fd, SIOCLIFREMOVEIF, &lifr) == -1 && 1083 errno != ENXIO) { 1084 dhcpmsg(MSG_ERR, "unplumb_lif: SIOCLIFREMOVEIF %s", 1085 lif->lif_name); 1086 } 1087 lif->lif_plumbed = B_FALSE; 1088 } 1089 1090 /* 1091 * Special case: if we're "unplumbing" the main LIF for DHCPv4, then 1092 * just canonize it and remove it from the lease. The DAD wait flags 1093 * are handled by canonize_lif or by remove_lif. 1094 */ 1095 if ((dlp = lif->lif_lease) != NULL && dlp->dl_smach->dsm_lif == lif) { 1096 canonize_lif(lif, B_TRUE); 1097 cancel_lif_timers(lif); 1098 if (lif->lif_declined != NULL) { 1099 dlp->dl_smach->dsm_lif_down--; 1100 lif->lif_declined = NULL; 1101 } 1102 dlp->dl_nlifs = 0; 1103 dlp->dl_lifs = NULL; 1104 lif->lif_lease = NULL; 1105 release_lif(lif); 1106 } else { 1107 remove_lif(lif); 1108 } 1109 } 1110 1111 /* 1112 * attach_lif(): create a new logical interface, creating the physical 1113 * interface as necessary. 1114 * 1115 * input: const char *: the logical interface name 1116 * boolean_t: B_TRUE for IPv6 1117 * int *: set to DHCP_IPC_E_* if creation fails 1118 * output: dhcp_lif_t *: pointer to new entry, or NULL on failure 1119 */ 1120 1121 dhcp_lif_t * 1122 attach_lif(const char *lname, boolean_t isv6, int *error) 1123 { 1124 dhcp_pif_t *pif; 1125 char pname[LIFNAMSIZ], *cp; 1126 1127 (void) strlcpy(pname, lname, sizeof (pname)); 1128 if ((cp = strchr(pname, ':')) != NULL) 1129 *cp = '\0'; 1130 1131 if ((pif = lookup_pif_by_name(pname, isv6)) != NULL) 1132 hold_pif(pif); 1133 else if ((pif = insert_pif(pname, isv6, error)) == NULL) 1134 return (NULL); 1135 1136 if (lookup_lif_by_name(lname, pif) != NULL) { 1137 dhcpmsg(MSG_ERROR, "attach_lif: entry for %s already exists!", 1138 lname); 1139 release_pif(pif); 1140 *error = DHCP_IPC_E_INVIF; 1141 return (NULL); 1142 } 1143 1144 /* If LIF creation fails, then insert_lif discards our PIF hold */ 1145 return (insert_lif(pif, lname, error)); 1146 } 1147 1148 /* 1149 * set_lif_dhcp(): Set logical interface flags to show that it's managed 1150 * by DHCP. 1151 * 1152 * input: dhcp_lif_t *: the logical interface 1153 * output: int: set to DHCP_IPC_E_* if operation fails 1154 */ 1155 1156 int 1157 set_lif_dhcp(dhcp_lif_t *lif) 1158 { 1159 int fd; 1160 int err; 1161 struct lifreq lifr; 1162 dhcp_pif_t *pif = lif->lif_pif; 1163 1164 fd = pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1165 1166 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1167 1168 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1169 err = errno; 1170 dhcpmsg(MSG_ERR, "set_lif_dhcp: SIOCGLIFFLAGS for %s", 1171 lif->lif_name); 1172 return (err == ENXIO ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT); 1173 } 1174 lif->lif_flags = lifr.lifr_flags; 1175 1176 /* 1177 * Check for conflicting sources of address control, and other 1178 * unacceptable configurations. 1179 */ 1180 if (lifr.lifr_flags & (IFF_LOOPBACK|IFF_ADDRCONF|IFF_TEMPORARY| 1181 IFF_VIRTUAL)) { 1182 dhcpmsg(MSG_ERR, "set_lif_dhcp: cannot use %s: flags are %llx", 1183 lif->lif_name, lifr.lifr_flags); 1184 return (DHCP_IPC_E_INVIF); 1185 } 1186 1187 /* 1188 * If IFF_DHCPRUNNING is already set on the interface and we're not 1189 * adopting it, the agent probably crashed and burned. Note it, but 1190 * don't let it stop the proceedings (we're pretty sure we're not 1191 * already running, since we were able to bind to our IPC port). 1192 */ 1193 if (lifr.lifr_flags & IFF_DHCPRUNNING) { 1194 dhcpmsg(MSG_VERBOSE, "set_lif_dhcp: IFF_DHCPRUNNING already set" 1195 " on %s", lif->lif_name); 1196 } else { 1197 /* 1198 * If the lif is on an interface under IPMP, IFF_NOFAILOVER 1199 * must be set or the kernel will prevent us from setting 1200 * IFF_DHCPRUNNING (since the subsequent IFF_UP would lead to 1201 * migration). We set IFF_DEPRECATED too since the kernel 1202 * will set it automatically when setting IFF_NOFAILOVER, 1203 * causing our lif_flags value to grow stale. 1204 */ 1205 if (pif->pif_under_ipmp && !(lifr.lifr_flags & IFF_NOFAILOVER)) 1206 lifr.lifr_flags |= IFF_NOFAILOVER | IFF_DEPRECATED; 1207 1208 lifr.lifr_flags |= IFF_DHCPRUNNING; 1209 if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1) { 1210 dhcpmsg(MSG_ERR, "set_lif_dhcp: SIOCSLIFFLAGS for %s", 1211 lif->lif_name); 1212 return (DHCP_IPC_E_INT); 1213 } 1214 lif->lif_flags = lifr.lifr_flags; 1215 } 1216 return (DHCP_IPC_SUCCESS); 1217 } 1218 1219 /* 1220 * clear_lif_dhcp(): Clear logical interface flags to show that it's no longer 1221 * managed by DHCP. 1222 * 1223 * input: dhcp_lif_t *: the logical interface 1224 * output: none 1225 */ 1226 1227 static void 1228 clear_lif_dhcp(dhcp_lif_t *lif) 1229 { 1230 int fd; 1231 struct lifreq lifr; 1232 1233 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1234 1235 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1236 1237 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) 1238 return; 1239 1240 if (!(lifr.lifr_flags & IFF_DHCPRUNNING)) 1241 return; 1242 1243 lif->lif_flags = lifr.lifr_flags &= ~IFF_DHCPRUNNING; 1244 (void) ioctl(fd, SIOCSLIFFLAGS, &lifr); 1245 } 1246 1247 static void 1248 update_pif_mtu(dhcp_pif_t *pif) 1249 { 1250 /* 1251 * Find the smallest requested MTU, if any, for the logical interfaces 1252 * on this physical interface: 1253 */ 1254 uint_t mtu = 0; 1255 for (dhcp_lif_t *lif = pif->pif_lifs; lif != NULL; 1256 lif = lif->lif_next) { 1257 if (lif->lif_mtu == 0) { 1258 /* 1259 * This logical interface has not requested a specific 1260 * MTU. 1261 */ 1262 continue; 1263 } 1264 1265 if (mtu == 0 || mtu > lif->lif_mtu) { 1266 mtu = lif->lif_mtu; 1267 } 1268 } 1269 1270 if (mtu == 0) { 1271 /* 1272 * There are no remaining requests for a specific MTU. Return 1273 * the interface to its original MTU. 1274 */ 1275 dhcpmsg(MSG_DEBUG2, "update_pif_mtu: restoring %s MTU to " 1276 "original %u", pif->pif_name, pif->pif_mtu_orig); 1277 mtu = pif->pif_mtu_orig; 1278 } 1279 1280 if (pif->pif_mtu == mtu) { 1281 /* 1282 * The MTU is already correct. 1283 */ 1284 dhcpmsg(MSG_DEBUG2, "update_pif_mtu: %s MTU is already %u", 1285 pif->pif_name, mtu); 1286 return; 1287 } 1288 1289 dhcpmsg(MSG_DEBUG, "update_pif_mtu: %s MTU change: %u -> %u", 1290 pif->pif_name, pif->pif_mtu, mtu); 1291 1292 struct lifreq lifr; 1293 (void) memset(&lifr, 0, sizeof (lifr)); 1294 (void) strlcpy(lifr.lifr_name, pif->pif_name, LIFNAMSIZ); 1295 lifr.lifr_mtu = mtu; 1296 1297 int fd = pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1298 if (ioctl(fd, SIOCSLIFMTU, &lifr) == -1) { 1299 dhcpmsg(MSG_ERR, "update_pif_mtu: SIOCSLIFMTU (%u) failed " 1300 "for %s", mtu, pif->pif_name); 1301 return; 1302 } 1303 1304 pif->pif_mtu = mtu; 1305 } 1306 1307 void 1308 set_lif_mtu(dhcp_lif_t *lif, uint_t mtu) 1309 { 1310 dhcpmsg(MSG_DEBUG, "set_lif_mtu: %s requests MTU %u", lif->lif_name, 1311 mtu); 1312 1313 lif->lif_mtu = mtu; 1314 update_pif_mtu(lif->lif_pif); 1315 } 1316 1317 void 1318 clear_lif_mtu(dhcp_lif_t *lif) 1319 { 1320 if (lif->lif_mtu != 0) { 1321 dhcpmsg(MSG_DEBUG, "clear_lif_mtu: %s clears MTU request", 1322 lif->lif_name); 1323 } 1324 1325 /* 1326 * Remove our prior request and update the physical interface. 1327 */ 1328 lif->lif_mtu = 0; 1329 update_pif_mtu(lif->lif_pif); 1330 } 1331 1332 /* 1333 * set_lif_deprecated(): Set the "deprecated" flag to tell users that this 1334 * address will be going away. As the interface is 1335 * going away, we don't care if there are errors. 1336 * 1337 * input: dhcp_lif_t *: the logical interface 1338 * output: none 1339 */ 1340 1341 void 1342 set_lif_deprecated(dhcp_lif_t *lif) 1343 { 1344 int fd; 1345 struct lifreq lifr; 1346 1347 if (lif->lif_flags & IFF_DEPRECATED) 1348 return; 1349 1350 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1351 1352 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1353 1354 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) 1355 return; 1356 1357 if (lifr.lifr_flags & IFF_DEPRECATED) 1358 return; 1359 1360 lifr.lifr_flags |= IFF_DEPRECATED; 1361 (void) ioctl(fd, SIOCSLIFFLAGS, &lifr); 1362 lif->lif_flags = lifr.lifr_flags; 1363 } 1364 1365 /* 1366 * clear_lif_deprecated(): Clear the "deprecated" flag to tell users that this 1367 * address will not be going away. This happens if we 1368 * get a renewal after preferred lifetime but before 1369 * the valid lifetime. 1370 * 1371 * input: dhcp_lif_t *: the logical interface 1372 * output: boolean_t: B_TRUE on success. 1373 */ 1374 1375 boolean_t 1376 clear_lif_deprecated(dhcp_lif_t *lif) 1377 { 1378 int fd; 1379 struct lifreq lifr; 1380 1381 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1382 1383 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1384 1385 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1386 dhcpmsg(MSG_ERR, "clear_lif_deprecated: SIOCGLIFFLAGS for %s", 1387 lif->lif_name); 1388 return (B_FALSE); 1389 } 1390 1391 /* 1392 * Check for conflicting sources of address control, and other 1393 * unacceptable configurations. 1394 */ 1395 if (lifr.lifr_flags & (IFF_LOOPBACK|IFF_ADDRCONF|IFF_TEMPORARY| 1396 IFF_VIRTUAL)) { 1397 dhcpmsg(MSG_ERR, "clear_lif_deprecated: cannot use %s: flags " 1398 "are %llx", lif->lif_name, lifr.lifr_flags); 1399 return (B_FALSE); 1400 } 1401 1402 /* 1403 * Don't try to clear IFF_DEPRECATED if this is a test address, 1404 * since IPMP's use of IFF_DEPRECATED is not compatible with ours. 1405 */ 1406 if (lifr.lifr_flags & IFF_NOFAILOVER) 1407 return (B_TRUE); 1408 1409 if (!(lifr.lifr_flags & IFF_DEPRECATED)) 1410 return (B_TRUE); 1411 1412 lifr.lifr_flags &= ~IFF_DEPRECATED; 1413 if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1) { 1414 dhcpmsg(MSG_ERR, "clear_lif_deprecated: SIOCSLIFFLAGS for %s", 1415 lif->lif_name); 1416 return (B_FALSE); 1417 } else { 1418 lif->lif_flags = lifr.lifr_flags; 1419 return (B_TRUE); 1420 } 1421 } 1422 1423 /* 1424 * open_ip_lif(): open up an IP socket for I/O on a given LIF (v4 only). 1425 * 1426 * input: dhcp_lif_t *: the logical interface to operate on 1427 * in_addr_t: the address the socket will be bound to (in hbo) 1428 * boolean_t: B_TRUE if the address should be brought up (if needed) 1429 * output: boolean_t: B_TRUE if the socket was opened successfully. 1430 */ 1431 1432 boolean_t 1433 open_ip_lif(dhcp_lif_t *lif, in_addr_t addr_hbo, boolean_t bringup) 1434 { 1435 const char *errmsg; 1436 struct lifreq lifr; 1437 int on = 1; 1438 uchar_t ttl = 255; 1439 uint32_t ifindex; 1440 dhcp_pif_t *pif = lif->lif_pif; 1441 1442 if (lif->lif_sock_ip_fd != -1) { 1443 dhcpmsg(MSG_WARNING, "open_ip_lif: socket already open on %s", 1444 lif->lif_name); 1445 return (B_FALSE); 1446 } 1447 1448 lif->lif_sock_ip_fd = socket(AF_INET, SOCK_DGRAM, 0); 1449 if (lif->lif_sock_ip_fd == -1) { 1450 errmsg = "cannot create v4 socket"; 1451 goto failure; 1452 } 1453 1454 if (!bind_sock(lif->lif_sock_ip_fd, IPPORT_BOOTPC, addr_hbo)) { 1455 errmsg = "cannot bind v4 socket"; 1456 goto failure; 1457 } 1458 1459 /* 1460 * If we bound to INADDR_ANY, we have no IFF_UP source address to use. 1461 * Thus, enable IP_UNSPEC_SRC so that we can send packets with an 1462 * unspecified (0.0.0.0) address. Also, enable IP_DHCPINIT_IF so that 1463 * the IP module will accept unicast DHCP traffic regardless of the IP 1464 * address it's sent to. (We'll then figure out which packets are 1465 * ours based on the xid.) 1466 */ 1467 if (addr_hbo == INADDR_ANY) { 1468 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_UNSPEC_SRC, 1469 &on, sizeof (int)) == -1) { 1470 errmsg = "cannot set IP_UNSPEC_SRC"; 1471 goto failure; 1472 } 1473 1474 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_DHCPINIT_IF, 1475 &pif->pif_index, sizeof (int)) == -1) { 1476 errmsg = "cannot set IP_DHCPINIT_IF"; 1477 goto failure; 1478 } 1479 } 1480 1481 /* 1482 * Unfortunately, some hardware (such as the Linksys WRT54GC) 1483 * decrements the TTL *prior* to accepting DHCP traffic destined 1484 * for it. To workaround this, tell IP to use a TTL of 255 for 1485 * broadcast packets sent from this socket. 1486 */ 1487 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_BROADCAST_TTL, &ttl, 1488 sizeof (uchar_t)) == -1) { 1489 errmsg = "cannot set IP_BROADCAST_TTL"; 1490 goto failure; 1491 } 1492 1493 ifindex = pif->pif_under_ipmp ? pif->pif_grindex : pif->pif_index; 1494 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_BOUND_IF, &ifindex, 1495 sizeof (int)) == -1) { 1496 errmsg = "cannot set IP_BOUND_IF"; 1497 goto failure; 1498 } 1499 1500 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1501 if (ioctl(v4_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { 1502 errmsg = "cannot get interface flags"; 1503 goto failure; 1504 } 1505 1506 /* 1507 * If the lif is part of an interface under IPMP, IFF_NOFAILOVER must 1508 * be set or the kernel will prevent us from setting IFF_DHCPRUNNING 1509 * (since the subsequent IFF_UP would lead to migration). We set 1510 * IFF_DEPRECATED too since the kernel will set it automatically when 1511 * setting IFF_NOFAILOVER, causing our lif_flags value to grow stale. 1512 */ 1513 if (pif->pif_under_ipmp && !(lifr.lifr_flags & IFF_NOFAILOVER)) { 1514 lifr.lifr_flags |= IFF_NOFAILOVER | IFF_DEPRECATED; 1515 if (ioctl(v4_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1516 errmsg = "cannot set IFF_NOFAILOVER"; 1517 goto failure; 1518 } 1519 } 1520 lif->lif_flags = lifr.lifr_flags; 1521 1522 /* 1523 * If this is initial bringup, make sure the address we're acquiring a 1524 * lease on is IFF_UP. 1525 */ 1526 if (bringup && !(lifr.lifr_flags & IFF_UP)) { 1527 /* 1528 * Start from a clean slate. 1529 */ 1530 canonize_lif(lif, B_FALSE); 1531 1532 lifr.lifr_flags |= IFF_UP; 1533 if (ioctl(v4_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1534 errmsg = "cannot bring up"; 1535 goto failure; 1536 } 1537 lif->lif_flags = lifr.lifr_flags; 1538 1539 /* 1540 * When bringing 0.0.0.0 IFF_UP, the kernel changes the 1541 * netmask to 255.0.0.0, so re-fetch our expected netmask. 1542 */ 1543 if (ioctl(v4_sock_fd, SIOCGLIFNETMASK, &lifr) == -1) { 1544 errmsg = "cannot get netmask"; 1545 goto failure; 1546 } 1547 1548 lif->lif_netmask = 1549 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr.s_addr; 1550 } 1551 1552 /* 1553 * Usually, bringing up the address we're acquiring a lease on is 1554 * sufficient to allow packets to be sent and received via the 1555 * IP_BOUND_IF we did earlier. However, if we're acquiring a lease on 1556 * an underlying IPMP interface, the group interface will be used for 1557 * sending and receiving IP packets via IP_BOUND_IF. Thus, ensure at 1558 * least one address on the group interface is IFF_UP. 1559 */ 1560 if (bringup && pif->pif_under_ipmp) { 1561 (void) strlcpy(lifr.lifr_name, pif->pif_grifname, LIFNAMSIZ); 1562 if (ioctl(v4_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { 1563 errmsg = "cannot get IPMP group interface flags"; 1564 goto failure; 1565 } 1566 1567 if (!(lifr.lifr_flags & IFF_UP)) { 1568 lifr.lifr_flags |= IFF_UP; 1569 if (ioctl(v4_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1570 errmsg = "cannot bring up IPMP group interface"; 1571 goto failure; 1572 } 1573 } 1574 } 1575 1576 lif->lif_packet_id = iu_register_event(eh, lif->lif_sock_ip_fd, POLLIN, 1577 dhcp_packet_lif, lif); 1578 if (lif->lif_packet_id == -1) { 1579 errmsg = "cannot register to receive DHCP packets"; 1580 goto failure; 1581 } 1582 1583 return (B_TRUE); 1584 failure: 1585 dhcpmsg(MSG_ERR, "open_ip_lif: %s: %s", lif->lif_name, errmsg); 1586 close_ip_lif(lif); 1587 return (B_FALSE); 1588 } 1589 1590 /* 1591 * close_ip_lif(): close an IP socket for I/O on a given LIF. 1592 * 1593 * input: dhcp_lif_t *: the logical interface to operate on 1594 * output: none 1595 */ 1596 1597 void 1598 close_ip_lif(dhcp_lif_t *lif) 1599 { 1600 if (lif->lif_packet_id != -1) { 1601 (void) iu_unregister_event(eh, lif->lif_packet_id, NULL); 1602 lif->lif_packet_id = -1; 1603 } 1604 if (lif->lif_sock_ip_fd != -1) { 1605 (void) close(lif->lif_sock_ip_fd); 1606 lif->lif_sock_ip_fd = -1; 1607 } 1608 } 1609 1610 /* 1611 * lif_mark_decline(): mark a LIF as having been declined due to a duplicate 1612 * address or some other conflict. This is used in 1613 * send_declines() to report failure back to the server. 1614 * 1615 * input: dhcp_lif_t *: the logical interface to operate on 1616 * const char *: text string explaining why the address is declined 1617 * output: none 1618 */ 1619 1620 void 1621 lif_mark_decline(dhcp_lif_t *lif, const char *reason) 1622 { 1623 if (lif->lif_declined == NULL) { 1624 dhcp_lease_t *dlp; 1625 1626 lif->lif_declined = reason; 1627 if ((dlp = lif->lif_lease) != NULL) 1628 dlp->dl_smach->dsm_lif_down++; 1629 } 1630 } 1631 1632 /* 1633 * schedule_lif_timer(): schedules the LIF-related timer 1634 * 1635 * input: dhcp_lif_t *: the logical interface to operate on 1636 * dhcp_timer_t *: the timer to schedule 1637 * iu_tq_callback_t *: the callback to call upon firing 1638 * output: boolean_t: B_TRUE if the timer was scheduled successfully 1639 */ 1640 1641 boolean_t 1642 schedule_lif_timer(dhcp_lif_t *lif, dhcp_timer_t *dt, iu_tq_callback_t *expire) 1643 { 1644 /* 1645 * If there's a timer running, cancel it and release its lease 1646 * reference. 1647 */ 1648 if (dt->dt_id != -1) { 1649 if (!cancel_timer(dt)) 1650 return (B_FALSE); 1651 release_lif(lif); 1652 } 1653 1654 if (schedule_timer(dt, expire, lif)) { 1655 hold_lif(lif); 1656 return (B_TRUE); 1657 } else { 1658 dhcpmsg(MSG_WARNING, 1659 "schedule_lif_timer: cannot schedule timer"); 1660 return (B_FALSE); 1661 } 1662 } 1663 1664 /* 1665 * cancel_lif_timer(): cancels a LIF-related timer 1666 * 1667 * input: dhcp_lif_t *: the logical interface to operate on 1668 * dhcp_timer_t *: the timer to cancel 1669 * output: none 1670 */ 1671 1672 static void 1673 cancel_lif_timer(dhcp_lif_t *lif, dhcp_timer_t *dt) 1674 { 1675 if (dt->dt_id == -1) 1676 return; 1677 if (cancel_timer(dt)) { 1678 dhcpmsg(MSG_DEBUG2, 1679 "cancel_lif_timer: canceled expiry timer on %s", 1680 lif->lif_name); 1681 release_lif(lif); 1682 } else { 1683 dhcpmsg(MSG_WARNING, 1684 "cancel_lif_timer: cannot cancel timer on %s", 1685 lif->lif_name); 1686 } 1687 } 1688 1689 /* 1690 * cancel_lif_timers(): cancels the LIF-related timers 1691 * 1692 * input: dhcp_lif_t *: the logical interface to operate on 1693 * output: none 1694 */ 1695 1696 void 1697 cancel_lif_timers(dhcp_lif_t *lif) 1698 { 1699 cancel_lif_timer(lif, &lif->lif_preferred); 1700 cancel_lif_timer(lif, &lif->lif_expire); 1701 } 1702 1703 /* 1704 * get_max_mtu(): find the maximum MTU of all interfaces for I/O on common 1705 * file descriptors (v4_sock_fd and v6_sock_fd). 1706 * 1707 * input: boolean_t: B_TRUE for IPv6, B_FALSE for IPv4 1708 * output: none 1709 */ 1710 1711 uint_t 1712 get_max_mtu(boolean_t isv6) 1713 { 1714 uint_t *mtup = isv6 ? &cached_v6_max_mtu : &cached_v4_max_mtu; 1715 1716 if (*mtup == 0) { 1717 dhcp_pif_t *pif; 1718 dhcp_lif_t *lif; 1719 struct lifreq lifr; 1720 1721 /* Set an arbitrary lower bound */ 1722 *mtup = 1024; 1723 pif = isv6 ? v6root : v4root; 1724 for (; pif != NULL; pif = pif->pif_next) { 1725 for (lif = pif->pif_lifs; lif != NULL; 1726 lif = lif->lif_next) { 1727 (void) strlcpy(lifr.lifr_name, lif->lif_name, 1728 LIFNAMSIZ); 1729 if (ioctl(v4_sock_fd, SIOCGLIFMTU, &lifr) != 1730 -1 && lifr.lifr_mtu > *mtup) { 1731 *mtup = lifr.lifr_mtu; 1732 } 1733 } 1734 } 1735 } 1736 return (*mtup); 1737 } 1738 1739 /* 1740 * expired_lif_state(): summarize the state of expired LIFs on a given state 1741 * machine. 1742 * 1743 * input: dhcp_smach_t *: the state machine to scan 1744 * output: dhcp_expire_t: overall state 1745 */ 1746 1747 dhcp_expire_t 1748 expired_lif_state(dhcp_smach_t *dsmp) 1749 { 1750 dhcp_lease_t *dlp; 1751 dhcp_lif_t *lif; 1752 uint_t nlifs; 1753 uint_t numlifs; 1754 uint_t numexp; 1755 1756 numlifs = numexp = 0; 1757 for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlp->dl_next) { 1758 lif = dlp->dl_lifs; 1759 nlifs = dlp->dl_nlifs; 1760 numlifs += nlifs; 1761 for (; nlifs > 0; nlifs--, lif = lif->lif_next) { 1762 if (lif->lif_expired) 1763 numexp++; 1764 } 1765 } 1766 if (numlifs == 0) 1767 return (DHCP_EXP_NOLIFS); 1768 else if (numexp == 0) 1769 return (DHCP_EXP_NOEXP); 1770 else if (numlifs == numexp) 1771 return (DHCP_EXP_ALLEXP); 1772 else 1773 return (DHCP_EXP_SOMEEXP); 1774 } 1775 1776 /* 1777 * find_expired_lif(): find the first expired LIF on a given state machine 1778 * 1779 * input: dhcp_smach_t *: the state machine to scan 1780 * output: dhcp_lif_t *: the first expired LIF, or NULL if none. 1781 */ 1782 1783 dhcp_lif_t * 1784 find_expired_lif(dhcp_smach_t *dsmp) 1785 { 1786 dhcp_lease_t *dlp; 1787 dhcp_lif_t *lif; 1788 uint_t nlifs; 1789 1790 for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlp->dl_next) { 1791 lif = dlp->dl_lifs; 1792 nlifs = dlp->dl_nlifs; 1793 for (; nlifs > 0; nlifs--, lif = lif->lif_next) { 1794 if (lif->lif_expired) 1795 return (lif); 1796 } 1797 } 1798 return (NULL); 1799 } 1800 1801 /* 1802 * remove_v6_strays(): remove any stray interfaces marked as DHCPRUNNING. Used 1803 * only for DHCPv6. 1804 * 1805 * input: none 1806 * output: none 1807 */ 1808 1809 void 1810 remove_v6_strays(void) 1811 { 1812 struct lifnum lifn; 1813 struct lifconf lifc; 1814 struct lifreq *lifrp, *lifrmax; 1815 uint_t numifs; 1816 uint64_t flags; 1817 1818 /* 1819 * Get the approximate number of interfaces in the system. It's only 1820 * approximate because the system is dynamic -- interfaces may be 1821 * plumbed or unplumbed at any time. This is also the reason for the 1822 * "+ 10" fudge factor: we're trying to avoid unnecessary looping. 1823 */ 1824 (void) memset(&lifn, 0, sizeof (lifn)); 1825 lifn.lifn_family = AF_INET6; 1826 lifn.lifn_flags = LIFC_ALLZONES | LIFC_NOXMIT | LIFC_TEMPORARY; 1827 if (ioctl(v6_sock_fd, SIOCGLIFNUM, &lifn) == -1) { 1828 dhcpmsg(MSG_ERR, 1829 "remove_v6_strays: cannot read number of interfaces"); 1830 numifs = 10; 1831 } else { 1832 numifs = lifn.lifn_count + 10; 1833 } 1834 1835 /* 1836 * Get the interface information. We do this in a loop so that we can 1837 * recover from EINVAL from the kernel -- delivered when the buffer is 1838 * too small. 1839 */ 1840 (void) memset(&lifc, 0, sizeof (lifc)); 1841 lifc.lifc_family = AF_INET6; 1842 lifc.lifc_flags = LIFC_ALLZONES | LIFC_NOXMIT | LIFC_TEMPORARY; 1843 for (;;) { 1844 lifc.lifc_len = numifs * sizeof (*lifrp); 1845 lifrp = realloc(lifc.lifc_buf, lifc.lifc_len); 1846 if (lifrp == NULL) { 1847 dhcpmsg(MSG_ERR, 1848 "remove_v6_strays: cannot allocate memory"); 1849 free(lifc.lifc_buf); 1850 return; 1851 } 1852 lifc.lifc_buf = (caddr_t)lifrp; 1853 errno = 0; 1854 if (ioctl(v6_sock_fd, SIOCGLIFCONF, &lifc) == 0 && 1855 lifc.lifc_len < numifs * sizeof (*lifrp)) 1856 break; 1857 if (errno == 0 || errno == EINVAL) { 1858 numifs <<= 1; 1859 } else { 1860 dhcpmsg(MSG_ERR, "remove_v6_strays: SIOCGLIFCONF"); 1861 free(lifc.lifc_buf); 1862 return; 1863 } 1864 } 1865 1866 lifrmax = lifrp + lifc.lifc_len / sizeof (*lifrp); 1867 for (; lifrp < lifrmax; lifrp++) { 1868 /* 1869 * Get the interface flags; we're interested in the DHCP ones. 1870 */ 1871 if (ioctl(v6_sock_fd, SIOCGLIFFLAGS, lifrp) == -1) 1872 continue; 1873 flags = lifrp->lifr_flags; 1874 if (!(flags & IFF_DHCPRUNNING)) 1875 continue; 1876 /* 1877 * If the interface has a link-local address, then we don't 1878 * control it. Just remove the flag. 1879 */ 1880 if (ioctl(v6_sock_fd, SIOCGLIFADDR, lifrp) == -1) 1881 continue; 1882 if (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)&lifrp-> 1883 lifr_addr)->sin6_addr)) { 1884 lifrp->lifr_flags = flags & ~IFF_DHCPRUNNING; 1885 (void) ioctl(v6_sock_fd, SIOCSLIFFLAGS, lifrp); 1886 continue; 1887 } 1888 /* 1889 * All others are (or were) under our control. Clean up by 1890 * removing them. 1891 */ 1892 if (ioctl(v6_sock_fd, SIOCLIFREMOVEIF, lifrp) == 0) { 1893 dhcpmsg(MSG_DEBUG, "remove_v6_strays: removed %s", 1894 lifrp->lifr_name); 1895 } else if (errno != ENXIO) { 1896 dhcpmsg(MSG_ERR, 1897 "remove_v6_strays: SIOCLIFREMOVEIF %s", 1898 lifrp->lifr_name); 1899 } 1900 } 1901 free(lifc.lifc_buf); 1902 } 1903