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 = 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 = dlpi_open(pif->pif_name, dlia, sizeof (buf), 351 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) 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) 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 dhcpmsg(MSG_ERR, "verify_lif: SIOCGLIFFLAGS failed on %s", 783 lif->lif_name); 784 return (B_FALSE); 785 } 786 787 /* 788 * If important flags have changed, then abandon the interface. 789 */ 790 if ((lif->lif_flags ^ lifr.lifr_flags) & DHCP_IFF_WATCH) { 791 dhcpmsg(MSG_DEBUG, "verify_lif: unexpected flag change on %s: " 792 "%llx to %llx (%llx)", lif->lif_name, lif->lif_flags, 793 lifr.lifr_flags, (lif->lif_flags ^ lifr.lifr_flags) & 794 DHCP_IFF_WATCH); 795 return (B_FALSE); 796 } 797 798 /* 799 * Special case: if the interface has gone down as a duplicate, then 800 * this alone does _not_ mean that we're abandoning it just yet. Allow 801 * the state machine to handle this normally by trying to get a new 802 * lease. 803 */ 804 if ((lifr.lifr_flags & (IFF_UP|IFF_DUPLICATE)) == IFF_DUPLICATE) { 805 dhcpmsg(MSG_DEBUG, "verify_lif: duplicate address on %s", 806 lif->lif_name); 807 return (B_TRUE); 808 } 809 810 /* 811 * If the user has torn down or started up the interface manually, then 812 * abandon the lease. 813 */ 814 if ((lif->lif_flags ^ lifr.lifr_flags) & IFF_UP) { 815 dhcpmsg(MSG_DEBUG, "verify_lif: user has %s %s", 816 lifr.lifr_flags & IFF_UP ? "started up" : "shut down", 817 lif->lif_name); 818 return (B_FALSE); 819 } 820 821 /* 822 * Check for delete and recreate. 823 */ 824 if (ioctl(fd, SIOCGLIFINDEX, &lifr) == -1) { 825 dhcpmsg(MSG_ERR, "verify_lif: SIOCGLIFINDEX failed on %s", 826 lif->lif_name); 827 return (B_FALSE); 828 } 829 if (lifr.lifr_index != lif->lif_pif->pif_index) { 830 dhcpmsg(MSG_DEBUG, 831 "verify_lif: ifindex on %s changed: %u to %u", 832 lif->lif_name, lif->lif_pif->pif_index, lifr.lifr_index); 833 return (B_FALSE); 834 } 835 836 /* 837 * If the IP address, netmask, or broadcast address have changed, or 838 * the interface has been unplumbed, then we act like there has been an 839 * implicit drop. (Note that the netmask is under DHCP control for 840 * IPv4, but not for DHCPv6, and that IPv6 doesn't have broadcast 841 * addresses.) 842 */ 843 844 if (!checkaddr(lif, SIOCGLIFADDR, &lif->lif_v6addr, "local address")) 845 return (B_FALSE); 846 847 if (isv6) { 848 /* 849 * If it's not point-to-point, we're done. If it is, then 850 * check the peer's address as well. 851 */ 852 return (!(lif->lif_flags & IFF_POINTOPOINT) || 853 checkaddr(lif, SIOCGLIFDSTADDR, &lif->lif_v6peer, 854 "peer address")); 855 } else { 856 if (!checkaddr(lif, SIOCGLIFNETMASK, &lif->lif_v6mask, 857 "netmask")) 858 return (B_FALSE); 859 860 return (checkaddr(lif, 861 (lif->lif_flags & IFF_POINTOPOINT) ? SIOCGLIFDSTADDR : 862 SIOCGLIFBRDADDR, &lif->lif_v6peer, "peer address")); 863 } 864 } 865 866 /* 867 * canonize_lif(): puts the interface in a canonical (zeroed) form. This is 868 * used only on the "main" LIF for IPv4. All other interfaces 869 * are under dhcpagent control and are removed using 870 * unplumb_lif(). 871 * 872 * input: dhcp_lif_t *: the interface to canonize 873 * output: none 874 */ 875 876 static void 877 canonize_lif(dhcp_lif_t *lif) 878 { 879 boolean_t isv6; 880 int fd; 881 struct lifreq lifr; 882 883 /* 884 * If there's nothing here, then don't touch the interface. This can 885 * happen when an already-canonized LIF is recanonized. 886 */ 887 if (IN6_IS_ADDR_UNSPECIFIED(&lif->lif_v6addr)) 888 return; 889 890 isv6 = lif->lif_pif->pif_isv6; 891 dhcpmsg(MSG_VERBOSE, "canonizing IPv%d interface %s", 892 isv6 ? 6 : 4, lif->lif_name); 893 894 lif->lif_v6addr = my_in6addr_any; 895 lif->lif_v6mask = my_in6addr_any; 896 lif->lif_v6peer = my_in6addr_any; 897 898 (void) memset(&lifr, 0, sizeof (struct lifreq)); 899 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 900 901 fd = isv6 ? v6_sock_fd : v4_sock_fd; 902 903 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 904 dhcpmsg(MSG_ERR, "canonize_lif: can't get flags for %s", 905 lif->lif_name); 906 return; 907 } 908 909 /* Should not happen */ 910 if (!(lifr.lifr_flags & IFF_DHCPRUNNING)) { 911 dhcpmsg(MSG_INFO, 912 "canonize_lif: cannot clear %s; flags are %llx", 913 lif->lif_name, lifr.lifr_flags); 914 return; 915 } 916 917 /* 918 * clear the UP flag, but don't clear DHCPRUNNING since 919 * that should only be done when the interface is removed 920 * (see clear_lif_dhcp() and remove_lif()) 921 */ 922 923 lif->lif_flags = lifr.lifr_flags &= ~IFF_UP; 924 925 if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1) { 926 dhcpmsg(MSG_ERR, "canonize_lif: can't set flags for %s", 927 lif->lif_name); 928 return; 929 } 930 931 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 932 if (isv6) { 933 struct sockaddr_in6 *sin6 = 934 (struct sockaddr_in6 *)&lifr.lifr_addr; 935 936 sin6->sin6_family = AF_INET6; 937 sin6->sin6_addr = my_in6addr_any; 938 } else { 939 struct sockaddr_in *sinv = 940 (struct sockaddr_in *)&lifr.lifr_addr; 941 942 sinv->sin_family = AF_INET; 943 sinv->sin_addr.s_addr = htonl(INADDR_ANY); 944 } 945 946 if (ioctl(fd, SIOCSLIFADDR, &lifr) == -1) { 947 dhcpmsg(MSG_ERR, 948 "canonize_lif: can't clear local address on %s", 949 lif->lif_name); 950 } 951 952 /* Netmask is under in.ndpd control with IPv6 */ 953 if (!isv6 && ioctl(fd, SIOCSLIFNETMASK, &lifr) == -1) { 954 dhcpmsg(MSG_ERR, "canonize_lif: can't clear netmask on %s", 955 lif->lif_name); 956 } 957 958 if (lif->lif_flags & IFF_POINTOPOINT) { 959 if (ioctl(fd, SIOCSLIFDSTADDR, &lifr) == -1) { 960 dhcpmsg(MSG_ERR, 961 "canonize_lif: can't clear remote address on %s", 962 lif->lif_name); 963 } 964 } else if (!isv6) { 965 if (ioctl(fd, SIOCSLIFBRDADDR, &lifr) == -1) { 966 dhcpmsg(MSG_ERR, 967 "canonize_lif: can't clear broadcast address on %s", 968 lif->lif_name); 969 } 970 } 971 } 972 973 /* 974 * plumb_lif(): Adds the LIF to the system. This is used for all 975 * DHCPv6-derived interfaces. The returned LIF has a hold 976 * on it. 977 * 978 * input: dhcp_lif_t *: the interface to unplumb 979 * output: none 980 */ 981 982 dhcp_lif_t * 983 plumb_lif(dhcp_pif_t *pif, const in6_addr_t *addr) 984 { 985 dhcp_lif_t *lif; 986 char abuf[INET6_ADDRSTRLEN]; 987 struct lifreq lifr; 988 struct sockaddr_in6 *sin6; 989 int error; 990 991 (void) inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)); 992 993 for (lif = pif->pif_lifs; lif != NULL; lif = lif->lif_next) { 994 if (IN6_ARE_ADDR_EQUAL(&lif->lif_v6addr, addr)) { 995 dhcpmsg(MSG_ERR, 996 "plumb_lif: entry for %s already exists!", abuf); 997 return (NULL); 998 } 999 } 1000 1001 /* First, create a new zero-address logical interface */ 1002 (void) memset(&lifr, 0, sizeof (lifr)); 1003 (void) strlcpy(lifr.lifr_name, pif->pif_name, sizeof (lifr.lifr_name)); 1004 if (ioctl(v6_sock_fd, SIOCLIFADDIF, &lifr) == -1) { 1005 dhcpmsg(MSG_ERR, "plumb_lif: SIOCLIFADDIF %s", pif->pif_name); 1006 return (NULL); 1007 } 1008 1009 /* Next, set the netmask to all ones */ 1010 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1011 sin6->sin6_family = AF_INET6; 1012 (void) memset(&sin6->sin6_addr, 0xff, sizeof (sin6->sin6_addr)); 1013 if (ioctl(v6_sock_fd, SIOCSLIFNETMASK, &lifr) == -1) { 1014 dhcpmsg(MSG_ERR, "plumb_lif: SIOCSLIFNETMASK %s", 1015 lifr.lifr_name); 1016 goto failure; 1017 } 1018 1019 /* Now set the interface address */ 1020 sin6->sin6_addr = *addr; 1021 if (ioctl(v6_sock_fd, SIOCSLIFADDR, &lifr) == -1) { 1022 dhcpmsg(MSG_ERR, "plumb_lif: SIOCSLIFADDR %s %s", 1023 lifr.lifr_name, abuf); 1024 goto failure; 1025 } 1026 1027 /* Mark the interface up */ 1028 if (ioctl(v6_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { 1029 dhcpmsg(MSG_ERR, "plumb_lif: SIOCGLIFFLAGS %s", 1030 lifr.lifr_name); 1031 goto failure; 1032 } 1033 lifr.lifr_flags |= IFF_UP | IFF_DHCPRUNNING; 1034 if (ioctl(v6_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1035 dhcpmsg(MSG_ERR, "plumb_lif: SIOCSLIFFLAGS %s", 1036 lifr.lifr_name); 1037 goto failure; 1038 } 1039 1040 /* Now we can create the internal LIF structure */ 1041 hold_pif(pif); 1042 if ((lif = insert_lif(pif, lifr.lifr_name, &error)) == NULL) 1043 goto failure; 1044 1045 dhcpmsg(MSG_DEBUG, "plumb_lif: plumbed up %s on %s", abuf, 1046 lif->lif_name); 1047 lif->lif_plumbed = B_TRUE; 1048 1049 return (lif); 1050 1051 failure: 1052 if (ioctl(v6_sock_fd, SIOCLIFREMOVEIF, &lifr) == -1 && 1053 errno != ENXIO) { 1054 dhcpmsg(MSG_ERR, "plumb_lif: SIOCLIFREMOVEIF %s", 1055 lifr.lifr_name); 1056 } 1057 return (NULL); 1058 } 1059 1060 /* 1061 * unplumb_lif(): Removes the LIF from dhcpagent and the system. This is used 1062 * for all interfaces configured by DHCP (those in leases). 1063 * 1064 * input: dhcp_lif_t *: the interface to unplumb 1065 * output: none 1066 */ 1067 1068 void 1069 unplumb_lif(dhcp_lif_t *lif) 1070 { 1071 dhcp_lease_t *dlp; 1072 1073 if (lif->lif_plumbed) { 1074 struct lifreq lifr; 1075 1076 (void) memset(&lifr, 0, sizeof (lifr)); 1077 (void) strlcpy(lifr.lifr_name, lif->lif_name, 1078 sizeof (lifr.lifr_name)); 1079 if (ioctl(v6_sock_fd, SIOCLIFREMOVEIF, &lifr) == -1 && 1080 errno != ENXIO) { 1081 dhcpmsg(MSG_ERR, "unplumb_lif: SIOCLIFREMOVEIF %s", 1082 lif->lif_name); 1083 } 1084 lif->lif_plumbed = B_FALSE; 1085 } 1086 lif->lif_flags = 0; 1087 /* 1088 * Special case: if we're "unplumbing" the main LIF for DHCPv4, then 1089 * just canonize it and remove it from the lease. 1090 */ 1091 if ((dlp = lif->lif_lease) != NULL && dlp->dl_smach->dsm_lif == lif) { 1092 canonize_lif(lif); 1093 cancel_lif_timers(lif); 1094 if (lif->lif_declined != NULL) { 1095 dlp->dl_smach->dsm_lif_down--; 1096 lif->lif_declined = NULL; 1097 } 1098 dlp->dl_nlifs = 0; 1099 dlp->dl_lifs = NULL; 1100 lif->lif_lease = NULL; 1101 release_lif(lif); 1102 } else { 1103 remove_lif(lif); 1104 } 1105 } 1106 1107 /* 1108 * attach_lif(): create a new logical interface, creating the physical 1109 * interface as necessary. 1110 * 1111 * input: const char *: the logical interface name 1112 * boolean_t: B_TRUE for IPv6 1113 * int *: set to DHCP_IPC_E_* if creation fails 1114 * output: dhcp_lif_t *: pointer to new entry, or NULL on failure 1115 */ 1116 1117 dhcp_lif_t * 1118 attach_lif(const char *lname, boolean_t isv6, int *error) 1119 { 1120 dhcp_pif_t *pif; 1121 char pname[LIFNAMSIZ], *cp; 1122 1123 (void) strlcpy(pname, lname, sizeof (pname)); 1124 if ((cp = strchr(pname, ':')) != NULL) 1125 *cp = '\0'; 1126 1127 if ((pif = lookup_pif_by_name(pname, isv6)) != NULL) 1128 hold_pif(pif); 1129 else if ((pif = insert_pif(pname, isv6, error)) == NULL) 1130 return (NULL); 1131 1132 if (lookup_lif_by_name(lname, pif) != NULL) { 1133 dhcpmsg(MSG_ERROR, "attach_lif: entry for %s already exists!", 1134 lname); 1135 release_pif(pif); 1136 *error = DHCP_IPC_E_INVIF; 1137 return (NULL); 1138 } 1139 1140 /* If LIF creation fails, then insert_lif discards our PIF hold */ 1141 return (insert_lif(pif, lname, error)); 1142 } 1143 1144 /* 1145 * set_lif_dhcp(): Set logical interface flags to show that it's managed 1146 * by DHCP. 1147 * 1148 * input: dhcp_lif_t *: the logical interface 1149 * boolean_t: B_TRUE if adopting 1150 * output: int: set to DHCP_IPC_E_* if operation fails 1151 */ 1152 1153 int 1154 set_lif_dhcp(dhcp_lif_t *lif, boolean_t is_adopting) 1155 { 1156 int fd; 1157 int err; 1158 struct lifreq lifr; 1159 1160 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1161 1162 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1163 1164 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1165 err = errno; 1166 dhcpmsg(MSG_ERR, "set_lif_dhcp: SIOCGLIFFLAGS for %s", 1167 lif->lif_name); 1168 return (err == ENXIO ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT); 1169 } 1170 lif->lif_flags = lifr.lifr_flags; 1171 1172 /* 1173 * Check for conflicting sources of address control, and other 1174 * unacceptable configurations. 1175 */ 1176 if (lifr.lifr_flags & (IFF_LOOPBACK|IFF_ADDRCONF|IFF_MIPRUNNING| 1177 IFF_TEMPORARY|IFF_VIRTUAL)) { 1178 dhcpmsg(MSG_ERR, "set_lif_dhcp: cannot use %s: flags are %llx", 1179 lif->lif_name, lifr.lifr_flags); 1180 return (DHCP_IPC_E_INVIF); 1181 } 1182 1183 /* 1184 * if DHCPRUNNING is already set on the interface and we're 1185 * not adopting it, the agent probably crashed and burned. 1186 * note it, but don't let it stop the proceedings. we're 1187 * pretty sure we're not already running, since we wouldn't 1188 * have been able to bind to our IPC port. 1189 */ 1190 1191 if (lifr.lifr_flags & IFF_DHCPRUNNING) { 1192 if (!is_adopting) { 1193 dhcpmsg(MSG_WARNING, "set_lif_dhcp: DHCP flag already " 1194 "set on %s", lif->lif_name); 1195 } 1196 } else { 1197 lifr.lifr_flags |= IFF_DHCPRUNNING; 1198 if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1) { 1199 dhcpmsg(MSG_ERR, "set_lif_dhcp: SIOCSLIFFLAGS for %s", 1200 lif->lif_name); 1201 return (DHCP_IPC_E_INT); 1202 } 1203 lif->lif_flags = lifr.lifr_flags; 1204 } 1205 return (DHCP_IPC_SUCCESS); 1206 } 1207 1208 /* 1209 * clear_lif_dhcp(): Clear logical interface flags to show that it's no longer 1210 * managed by DHCP. 1211 * 1212 * input: dhcp_lif_t *: the logical interface 1213 * output: none 1214 */ 1215 1216 static void 1217 clear_lif_dhcp(dhcp_lif_t *lif) 1218 { 1219 int fd; 1220 struct lifreq lifr; 1221 1222 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1223 1224 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1225 1226 if (!(lif->lif_flags & IFF_DHCPRUNNING)) 1227 return; 1228 1229 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) 1230 return; 1231 1232 if (!(lifr.lifr_flags & IFF_DHCPRUNNING)) 1233 return; 1234 1235 lif->lif_flags = lifr.lifr_flags &= ~IFF_DHCPRUNNING; 1236 (void) ioctl(fd, SIOCSLIFFLAGS, &lifr); 1237 } 1238 1239 /* 1240 * set_lif_deprecated(): Set the "deprecated" flag to tell users that this 1241 * address will be going away. As the interface is 1242 * going away, we don't care if there are errors. 1243 * 1244 * input: dhcp_lif_t *: the logical interface 1245 * output: none 1246 */ 1247 1248 void 1249 set_lif_deprecated(dhcp_lif_t *lif) 1250 { 1251 int fd; 1252 struct lifreq lifr; 1253 1254 if (lif->lif_flags & IFF_DEPRECATED) 1255 return; 1256 1257 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1258 1259 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1260 1261 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) 1262 return; 1263 1264 if (lifr.lifr_flags & IFF_DEPRECATED) 1265 return; 1266 1267 lifr.lifr_flags |= IFF_DEPRECATED; 1268 (void) ioctl(fd, SIOCSLIFFLAGS, &lifr); 1269 lif->lif_flags = lifr.lifr_flags; 1270 } 1271 1272 /* 1273 * clear_lif_deprecated(): Clear the "deprecated" flag to tell users that this 1274 * address will not be going away. This happens if we 1275 * get a renewal after preferred lifetime but before 1276 * the valid lifetime. 1277 * 1278 * input: dhcp_lif_t *: the logical interface 1279 * output: boolean_t: B_TRUE on success. 1280 */ 1281 1282 boolean_t 1283 clear_lif_deprecated(dhcp_lif_t *lif) 1284 { 1285 int fd; 1286 struct lifreq lifr; 1287 1288 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1289 1290 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1291 1292 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1293 dhcpmsg(MSG_ERR, "clear_lif_deprecated: SIOCGLIFFLAGS for %s", 1294 lif->lif_name); 1295 return (B_FALSE); 1296 } 1297 1298 /* 1299 * Check for conflicting sources of address control, and other 1300 * unacceptable configurations. 1301 */ 1302 if (lifr.lifr_flags & (IFF_LOOPBACK|IFF_ADDRCONF|IFF_MIPRUNNING| 1303 IFF_TEMPORARY|IFF_VIRTUAL)) { 1304 dhcpmsg(MSG_ERR, "clear_lif_deprecated: cannot use %s: flags " 1305 "are %llx", lif->lif_name, lifr.lifr_flags); 1306 return (B_FALSE); 1307 } 1308 1309 if (!(lifr.lifr_flags & IFF_DEPRECATED)) 1310 return (B_TRUE); 1311 1312 lifr.lifr_flags &= ~IFF_DEPRECATED; 1313 if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1) { 1314 dhcpmsg(MSG_ERR, "clear_lif_deprecated: SIOCSLIFFLAGS for %s", 1315 lif->lif_name); 1316 return (B_FALSE); 1317 } else { 1318 lif->lif_flags = lifr.lifr_flags; 1319 return (B_TRUE); 1320 } 1321 } 1322 1323 /* 1324 * open_ip_lif(): open up an IP socket for I/O on a given LIF (v4 only). 1325 * 1326 * input: dhcp_lif_t *: the logical interface to operate on 1327 * output: boolean_t: B_TRUE if the socket was opened successfully. 1328 */ 1329 1330 boolean_t 1331 open_ip_lif(dhcp_lif_t *lif) 1332 { 1333 if (lif->lif_sock_ip_fd != -1) { 1334 dhcpmsg(MSG_WARNING, "open_ip_lif: socket already open on %s", 1335 lif->lif_name); 1336 return (B_FALSE); 1337 } 1338 1339 lif->lif_sock_ip_fd = socket(AF_INET, SOCK_DGRAM, 0); 1340 if (lif->lif_sock_ip_fd == -1) { 1341 dhcpmsg(MSG_ERR, "open_ip_lif: cannot create v4 socket on %s", 1342 lif->lif_name); 1343 return (B_FALSE); 1344 } 1345 1346 if (!bind_sock(lif->lif_sock_ip_fd, IPPORT_BOOTPC, 1347 ntohl(lif->lif_addr))) { 1348 dhcpmsg(MSG_ERR, "open_ip_lif: cannot bind v4 socket on %s", 1349 lif->lif_name); 1350 return (B_FALSE); 1351 } 1352 1353 lif->lif_acknak_id = iu_register_event(eh, lif->lif_sock_ip_fd, POLLIN, 1354 dhcp_acknak_lif, lif); 1355 if (lif->lif_acknak_id == -1) { 1356 dhcpmsg(MSG_WARNING, "open_ip_lif: cannot register to " 1357 "receive IP unicast"); 1358 close_ip_lif(lif); 1359 return (B_FALSE); 1360 } 1361 return (B_TRUE); 1362 } 1363 1364 /* 1365 * close_ip_lif(): close an IP socket for I/O on a given LIF. 1366 * 1367 * input: dhcp_lif_t *: the logical interface to operate on 1368 * output: none 1369 */ 1370 1371 void 1372 close_ip_lif(dhcp_lif_t *lif) 1373 { 1374 if (lif->lif_acknak_id != -1) { 1375 (void) iu_unregister_event(eh, lif->lif_acknak_id, NULL); 1376 lif->lif_acknak_id = -1; 1377 } 1378 if (lif->lif_sock_ip_fd != -1) { 1379 (void) close(lif->lif_sock_ip_fd); 1380 lif->lif_sock_ip_fd = -1; 1381 } 1382 } 1383 1384 /* 1385 * lif_mark_decline(): mark a LIF as having been declined due to a duplicate 1386 * address or some other conflict. This is used in 1387 * send_declines() to report failure back to the server. 1388 * 1389 * input: dhcp_lif_t *: the logical interface to operate on 1390 * const char *: text string explaining why the address is declined 1391 * output: none 1392 */ 1393 1394 void 1395 lif_mark_decline(dhcp_lif_t *lif, const char *reason) 1396 { 1397 if (lif->lif_declined == NULL) { 1398 dhcp_lease_t *dlp; 1399 1400 lif->lif_declined = reason; 1401 if ((dlp = lif->lif_lease) != NULL) 1402 dlp->dl_smach->dsm_lif_down++; 1403 } 1404 } 1405 1406 /* 1407 * schedule_lif_timer(): schedules the LIF-related timer 1408 * 1409 * input: dhcp_lif_t *: the logical interface to operate on 1410 * dhcp_timer_t *: the timer to schedule 1411 * iu_tq_callback_t *: the callback to call upon firing 1412 * output: boolean_t: B_TRUE if the timer was scheduled successfully 1413 */ 1414 1415 boolean_t 1416 schedule_lif_timer(dhcp_lif_t *lif, dhcp_timer_t *dt, iu_tq_callback_t *expire) 1417 { 1418 /* 1419 * If there's a timer running, cancel it and release its lease 1420 * reference. 1421 */ 1422 if (dt->dt_id != -1) { 1423 if (!cancel_timer(dt)) 1424 return (B_FALSE); 1425 release_lif(lif); 1426 } 1427 1428 if (schedule_timer(dt, expire, lif)) { 1429 hold_lif(lif); 1430 return (B_TRUE); 1431 } else { 1432 dhcpmsg(MSG_WARNING, 1433 "schedule_lif_timer: cannot schedule timer"); 1434 return (B_FALSE); 1435 } 1436 } 1437 1438 /* 1439 * cancel_lif_timer(): cancels a LIF-related timer 1440 * 1441 * input: dhcp_lif_t *: the logical interface to operate on 1442 * dhcp_timer_t *: the timer to cancel 1443 * output: none 1444 */ 1445 1446 static void 1447 cancel_lif_timer(dhcp_lif_t *lif, dhcp_timer_t *dt) 1448 { 1449 if (dt->dt_id == -1) 1450 return; 1451 if (cancel_timer(dt)) { 1452 dhcpmsg(MSG_DEBUG2, 1453 "cancel_lif_timer: canceled expiry timer on %s", 1454 lif->lif_name); 1455 release_lif(lif); 1456 } else { 1457 dhcpmsg(MSG_WARNING, 1458 "cancel_lif_timer: cannot cancel timer on %s", 1459 lif->lif_name); 1460 } 1461 } 1462 1463 /* 1464 * cancel_lif_timers(): cancels the LIF-related timers 1465 * 1466 * input: dhcp_lif_t *: the logical interface to operate on 1467 * output: none 1468 */ 1469 1470 void 1471 cancel_lif_timers(dhcp_lif_t *lif) 1472 { 1473 cancel_lif_timer(lif, &lif->lif_preferred); 1474 cancel_lif_timer(lif, &lif->lif_expire); 1475 } 1476 1477 /* 1478 * get_max_mtu(): find the maximum MTU of all interfaces for I/O on common 1479 * file descriptors (v4_sock_fd and v6_sock_fd). 1480 * 1481 * input: boolean_t: B_TRUE for IPv6, B_FALSE for IPv4 1482 * output: none 1483 */ 1484 1485 uint_t 1486 get_max_mtu(boolean_t isv6) 1487 { 1488 uint_t *mtup = isv6 ? &cached_v6_max_mtu : &cached_v4_max_mtu; 1489 1490 if (*mtup == 0) { 1491 dhcp_pif_t *pif; 1492 dhcp_lif_t *lif; 1493 struct lifreq lifr; 1494 1495 /* Set an arbitrary lower bound */ 1496 *mtup = 1024; 1497 pif = isv6 ? v6root : v4root; 1498 for (; pif != NULL; pif = pif->pif_next) { 1499 for (lif = pif->pif_lifs; lif != NULL; 1500 lif = lif->lif_next) { 1501 (void) strlcpy(lifr.lifr_name, lif->lif_name, 1502 LIFNAMSIZ); 1503 if (ioctl(v4_sock_fd, SIOCGLIFMTU, &lifr) != 1504 -1 && lifr.lifr_mtu > *mtup) { 1505 *mtup = lifr.lifr_mtu; 1506 } 1507 } 1508 } 1509 } 1510 return (*mtup); 1511 } 1512 1513 /* 1514 * expired_lif_state(): summarize the state of expired LIFs on a given state 1515 * machine. 1516 * 1517 * input: dhcp_smach_t *: the state machine to scan 1518 * output: dhcp_expire_t: overall state 1519 */ 1520 1521 dhcp_expire_t 1522 expired_lif_state(dhcp_smach_t *dsmp) 1523 { 1524 dhcp_lease_t *dlp; 1525 dhcp_lif_t *lif; 1526 uint_t nlifs; 1527 uint_t numlifs; 1528 uint_t numexp; 1529 1530 numlifs = numexp = 0; 1531 for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlp->dl_next) { 1532 lif = dlp->dl_lifs; 1533 nlifs = dlp->dl_nlifs; 1534 numlifs += nlifs; 1535 for (; nlifs > 0; nlifs--, lif = lif->lif_next) { 1536 if (lif->lif_expired) 1537 numexp++; 1538 } 1539 } 1540 if (numlifs == 0) 1541 return (DHCP_EXP_NOLIFS); 1542 else if (numexp == 0) 1543 return (DHCP_EXP_NOEXP); 1544 else if (numlifs == numexp) 1545 return (DHCP_EXP_ALLEXP); 1546 else 1547 return (DHCP_EXP_SOMEEXP); 1548 } 1549 1550 /* 1551 * find_expired_lif(): find the first expired LIF on a given state machine 1552 * 1553 * input: dhcp_smach_t *: the state machine to scan 1554 * output: dhcp_lif_t *: the first expired LIF, or NULL if none. 1555 */ 1556 1557 dhcp_lif_t * 1558 find_expired_lif(dhcp_smach_t *dsmp) 1559 { 1560 dhcp_lease_t *dlp; 1561 dhcp_lif_t *lif; 1562 uint_t nlifs; 1563 1564 for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlp->dl_next) { 1565 lif = dlp->dl_lifs; 1566 nlifs = dlp->dl_nlifs; 1567 for (; nlifs > 0; nlifs--, lif = lif->lif_next) { 1568 if (lif->lif_expired) 1569 return (lif); 1570 } 1571 } 1572 return (NULL); 1573 } 1574 1575 /* 1576 * remove_v6_strays(): remove any stray interfaces marked as DHCPRUNNING. Used 1577 * only for DHCPv6. 1578 * 1579 * input: none 1580 * output: none 1581 */ 1582 1583 void 1584 remove_v6_strays(void) 1585 { 1586 struct lifnum lifn; 1587 struct lifconf lifc; 1588 struct lifreq *lifrp, *lifrmax; 1589 uint_t numifs; 1590 uint64_t flags; 1591 1592 /* 1593 * Get the approximate number of interfaces in the system. It's only 1594 * approximate because the system is dynamic -- interfaces may be 1595 * plumbed or unplumbed at any time. This is also the reason for the 1596 * "+ 10" fudge factor: we're trying to avoid unnecessary looping. 1597 */ 1598 (void) memset(&lifn, 0, sizeof (lifn)); 1599 lifn.lifn_family = AF_INET6; 1600 lifn.lifn_flags = LIFC_ALLZONES | LIFC_NOXMIT | LIFC_TEMPORARY; 1601 if (ioctl(v6_sock_fd, SIOCGLIFNUM, &lifn) == -1) { 1602 dhcpmsg(MSG_ERR, 1603 "remove_v6_strays: cannot read number of interfaces"); 1604 numifs = 10; 1605 } else { 1606 numifs = lifn.lifn_count + 10; 1607 } 1608 1609 /* 1610 * Get the interface information. We do this in a loop so that we can 1611 * recover from EINVAL from the kernel -- delivered when the buffer is 1612 * too small. 1613 */ 1614 (void) memset(&lifc, 0, sizeof (lifc)); 1615 lifc.lifc_family = AF_INET6; 1616 lifc.lifc_flags = LIFC_ALLZONES | LIFC_NOXMIT | LIFC_TEMPORARY; 1617 for (;;) { 1618 lifc.lifc_len = numifs * sizeof (*lifrp); 1619 lifrp = realloc(lifc.lifc_buf, lifc.lifc_len); 1620 if (lifrp == NULL) { 1621 dhcpmsg(MSG_ERR, 1622 "remove_v6_strays: cannot allocate memory"); 1623 free(lifc.lifc_buf); 1624 return; 1625 } 1626 lifc.lifc_buf = (caddr_t)lifrp; 1627 errno = 0; 1628 if (ioctl(v6_sock_fd, SIOCGLIFCONF, &lifc) == 0 && 1629 lifc.lifc_len < numifs * sizeof (*lifrp)) 1630 break; 1631 if (errno == 0 || errno == EINVAL) { 1632 numifs <<= 1; 1633 } else { 1634 dhcpmsg(MSG_ERR, "remove_v6_strays: SIOCGLIFCONF"); 1635 free(lifc.lifc_buf); 1636 return; 1637 } 1638 } 1639 1640 lifrmax = lifrp + lifc.lifc_len / sizeof (*lifrp); 1641 for (; lifrp < lifrmax; lifrp++) { 1642 /* 1643 * Get the interface flags; we're interested in the DHCP ones. 1644 */ 1645 if (ioctl(v6_sock_fd, SIOCGLIFFLAGS, lifrp) == -1) 1646 continue; 1647 flags = lifrp->lifr_flags; 1648 if (!(flags & IFF_DHCPRUNNING)) 1649 continue; 1650 /* 1651 * If the interface has a link-local address, then we don't 1652 * control it. Just remove the flag. 1653 */ 1654 if (ioctl(v6_sock_fd, SIOCGLIFADDR, lifrp) == -1) 1655 continue; 1656 if (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)&lifrp-> 1657 lifr_addr)->sin6_addr)) { 1658 lifrp->lifr_flags = flags & ~IFF_DHCPRUNNING; 1659 (void) ioctl(v6_sock_fd, SIOCSLIFFLAGS, lifrp); 1660 continue; 1661 } 1662 /* 1663 * All others are (or were) under our control. Clean up by 1664 * removing them. 1665 */ 1666 if (ioctl(v6_sock_fd, SIOCLIFREMOVEIF, lifrp) == 0) { 1667 dhcpmsg(MSG_DEBUG, "remove_v6_strays: removed %s", 1668 lifrp->lifr_name); 1669 } else if (errno != ENXIO) { 1670 dhcpmsg(MSG_ERR, 1671 "remove_v6_strays: SIOCLIFREMOVEIF %s", 1672 lifrp->lifr_name); 1673 } 1674 } 1675 free(lifc.lifc_buf); 1676 } 1677