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