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