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