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