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