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 * output: int: set to DHCP_IPC_E_* if operation fails 1120 */ 1121 1122 int 1123 set_lif_dhcp(dhcp_lif_t *lif) 1124 { 1125 int fd; 1126 int err; 1127 struct lifreq lifr; 1128 dhcp_pif_t *pif = lif->lif_pif; 1129 1130 fd = pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1131 1132 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1133 1134 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1135 err = errno; 1136 dhcpmsg(MSG_ERR, "set_lif_dhcp: SIOCGLIFFLAGS for %s", 1137 lif->lif_name); 1138 return (err == ENXIO ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT); 1139 } 1140 lif->lif_flags = lifr.lifr_flags; 1141 1142 /* 1143 * Check for conflicting sources of address control, and other 1144 * unacceptable configurations. 1145 */ 1146 if (lifr.lifr_flags & (IFF_LOOPBACK|IFF_ADDRCONF|IFF_TEMPORARY| 1147 IFF_VIRTUAL)) { 1148 dhcpmsg(MSG_ERR, "set_lif_dhcp: cannot use %s: flags are %llx", 1149 lif->lif_name, lifr.lifr_flags); 1150 return (DHCP_IPC_E_INVIF); 1151 } 1152 1153 /* 1154 * If IFF_DHCPRUNNING is already set on the interface and we're not 1155 * adopting it, the agent probably crashed and burned. Note it, but 1156 * don't let it stop the proceedings (we're pretty sure we're not 1157 * already running, since we were able to bind to our IPC port). 1158 */ 1159 if (lifr.lifr_flags & IFF_DHCPRUNNING) { 1160 dhcpmsg(MSG_VERBOSE, "set_lif_dhcp: IFF_DHCPRUNNING already set" 1161 " on %s", lif->lif_name); 1162 } else { 1163 /* 1164 * If the lif is on an interface under IPMP, IFF_NOFAILOVER 1165 * must be set or the kernel will prevent us from setting 1166 * IFF_DHCPRUNNING (since the subsequent IFF_UP would lead to 1167 * migration). We set IFF_DEPRECATED too since the kernel 1168 * will set it automatically when setting IFF_NOFAILOVER, 1169 * causing our lif_flags value to grow stale. 1170 */ 1171 if (pif->pif_under_ipmp && !(lifr.lifr_flags & IFF_NOFAILOVER)) 1172 lifr.lifr_flags |= IFF_NOFAILOVER | IFF_DEPRECATED; 1173 1174 lifr.lifr_flags |= IFF_DHCPRUNNING; 1175 if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1) { 1176 dhcpmsg(MSG_ERR, "set_lif_dhcp: SIOCSLIFFLAGS for %s", 1177 lif->lif_name); 1178 return (DHCP_IPC_E_INT); 1179 } 1180 lif->lif_flags = lifr.lifr_flags; 1181 } 1182 return (DHCP_IPC_SUCCESS); 1183 } 1184 1185 /* 1186 * clear_lif_dhcp(): Clear logical interface flags to show that it's no longer 1187 * managed by DHCP. 1188 * 1189 * input: dhcp_lif_t *: the logical interface 1190 * output: none 1191 */ 1192 1193 static void 1194 clear_lif_dhcp(dhcp_lif_t *lif) 1195 { 1196 int fd; 1197 struct lifreq lifr; 1198 1199 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1200 1201 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1202 1203 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) 1204 return; 1205 1206 if (!(lifr.lifr_flags & IFF_DHCPRUNNING)) 1207 return; 1208 1209 lif->lif_flags = lifr.lifr_flags &= ~IFF_DHCPRUNNING; 1210 (void) ioctl(fd, SIOCSLIFFLAGS, &lifr); 1211 } 1212 1213 /* 1214 * set_lif_deprecated(): Set the "deprecated" flag to tell users that this 1215 * address will be going away. As the interface is 1216 * going away, we don't care if there are errors. 1217 * 1218 * input: dhcp_lif_t *: the logical interface 1219 * output: none 1220 */ 1221 1222 void 1223 set_lif_deprecated(dhcp_lif_t *lif) 1224 { 1225 int fd; 1226 struct lifreq lifr; 1227 1228 if (lif->lif_flags & IFF_DEPRECATED) 1229 return; 1230 1231 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1232 1233 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1234 1235 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) 1236 return; 1237 1238 if (lifr.lifr_flags & IFF_DEPRECATED) 1239 return; 1240 1241 lifr.lifr_flags |= IFF_DEPRECATED; 1242 (void) ioctl(fd, SIOCSLIFFLAGS, &lifr); 1243 lif->lif_flags = lifr.lifr_flags; 1244 } 1245 1246 /* 1247 * clear_lif_deprecated(): Clear the "deprecated" flag to tell users that this 1248 * address will not be going away. This happens if we 1249 * get a renewal after preferred lifetime but before 1250 * the valid lifetime. 1251 * 1252 * input: dhcp_lif_t *: the logical interface 1253 * output: boolean_t: B_TRUE on success. 1254 */ 1255 1256 boolean_t 1257 clear_lif_deprecated(dhcp_lif_t *lif) 1258 { 1259 int fd; 1260 struct lifreq lifr; 1261 1262 fd = lif->lif_pif->pif_isv6 ? v6_sock_fd : v4_sock_fd; 1263 1264 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1265 1266 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1267 dhcpmsg(MSG_ERR, "clear_lif_deprecated: SIOCGLIFFLAGS for %s", 1268 lif->lif_name); 1269 return (B_FALSE); 1270 } 1271 1272 /* 1273 * Check for conflicting sources of address control, and other 1274 * unacceptable configurations. 1275 */ 1276 if (lifr.lifr_flags & (IFF_LOOPBACK|IFF_ADDRCONF|IFF_TEMPORARY| 1277 IFF_VIRTUAL)) { 1278 dhcpmsg(MSG_ERR, "clear_lif_deprecated: cannot use %s: flags " 1279 "are %llx", lif->lif_name, lifr.lifr_flags); 1280 return (B_FALSE); 1281 } 1282 1283 /* 1284 * Don't try to clear IFF_DEPRECATED if this is a test address, 1285 * since IPMP's use of IFF_DEPRECATED is not compatible with ours. 1286 */ 1287 if (lifr.lifr_flags & IFF_NOFAILOVER) 1288 return (B_TRUE); 1289 1290 if (!(lifr.lifr_flags & IFF_DEPRECATED)) 1291 return (B_TRUE); 1292 1293 lifr.lifr_flags &= ~IFF_DEPRECATED; 1294 if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1) { 1295 dhcpmsg(MSG_ERR, "clear_lif_deprecated: SIOCSLIFFLAGS for %s", 1296 lif->lif_name); 1297 return (B_FALSE); 1298 } else { 1299 lif->lif_flags = lifr.lifr_flags; 1300 return (B_TRUE); 1301 } 1302 } 1303 1304 /* 1305 * open_ip_lif(): open up an IP socket for I/O on a given LIF (v4 only). 1306 * 1307 * input: dhcp_lif_t *: the logical interface to operate on 1308 * in_addr_t: the address the socket will be bound to (in hbo) 1309 * boolean_t: B_TRUE if the address should be brought up (if needed) 1310 * output: boolean_t: B_TRUE if the socket was opened successfully. 1311 */ 1312 1313 boolean_t 1314 open_ip_lif(dhcp_lif_t *lif, in_addr_t addr_hbo, boolean_t bringup) 1315 { 1316 const char *errmsg; 1317 struct lifreq lifr; 1318 int on = 1; 1319 uchar_t ttl = 255; 1320 uint32_t ifindex; 1321 dhcp_pif_t *pif = lif->lif_pif; 1322 1323 if (lif->lif_sock_ip_fd != -1) { 1324 dhcpmsg(MSG_WARNING, "open_ip_lif: socket already open on %s", 1325 lif->lif_name); 1326 return (B_FALSE); 1327 } 1328 1329 lif->lif_sock_ip_fd = socket(AF_INET, SOCK_DGRAM, 0); 1330 if (lif->lif_sock_ip_fd == -1) { 1331 errmsg = "cannot create v4 socket"; 1332 goto failure; 1333 } 1334 1335 if (!bind_sock(lif->lif_sock_ip_fd, IPPORT_BOOTPC, addr_hbo)) { 1336 errmsg = "cannot bind v4 socket"; 1337 goto failure; 1338 } 1339 1340 /* 1341 * If we bound to INADDR_ANY, we have no IFF_UP source address to use. 1342 * Thus, enable IP_UNSPEC_SRC so that we can send packets with an 1343 * unspecified (0.0.0.0) address. Also, enable IP_DHCPINIT_IF so that 1344 * the IP module will accept unicast DHCP traffic regardless of the IP 1345 * address it's sent to. (We'll then figure out which packets are 1346 * ours based on the xid.) 1347 */ 1348 if (addr_hbo == INADDR_ANY) { 1349 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_UNSPEC_SRC, 1350 &on, sizeof (int)) == -1) { 1351 errmsg = "cannot set IP_UNSPEC_SRC"; 1352 goto failure; 1353 } 1354 1355 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_DHCPINIT_IF, 1356 &pif->pif_index, sizeof (int)) == -1) { 1357 errmsg = "cannot set IP_DHCPINIT_IF"; 1358 goto failure; 1359 } 1360 } 1361 1362 /* 1363 * Unfortunately, some hardware (such as the Linksys WRT54GC) 1364 * decrements the TTL *prior* to accepting DHCP traffic destined 1365 * for it. To workaround this, tell IP to use a TTL of 255 for 1366 * broadcast packets sent from this socket. 1367 */ 1368 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_BROADCAST_TTL, &ttl, 1369 sizeof (uchar_t)) == -1) { 1370 errmsg = "cannot set IP_BROADCAST_TTL"; 1371 goto failure; 1372 } 1373 1374 ifindex = pif->pif_under_ipmp ? pif->pif_grindex : pif->pif_index; 1375 if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_BOUND_IF, &ifindex, 1376 sizeof (int)) == -1) { 1377 errmsg = "cannot set IP_BOUND_IF"; 1378 goto failure; 1379 } 1380 1381 (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ); 1382 if (ioctl(v4_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { 1383 errmsg = "cannot get interface flags"; 1384 goto failure; 1385 } 1386 1387 /* 1388 * If the lif is part of an interface under IPMP, IFF_NOFAILOVER must 1389 * be set or the kernel will prevent us from setting IFF_DHCPRUNNING 1390 * (since the subsequent IFF_UP would lead to migration). We set 1391 * IFF_DEPRECATED too since the kernel will set it automatically when 1392 * setting IFF_NOFAILOVER, causing our lif_flags value to grow stale. 1393 */ 1394 if (pif->pif_under_ipmp && !(lifr.lifr_flags & IFF_NOFAILOVER)) { 1395 lifr.lifr_flags |= IFF_NOFAILOVER | IFF_DEPRECATED; 1396 if (ioctl(v4_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1397 errmsg = "cannot set IFF_NOFAILOVER"; 1398 goto failure; 1399 } 1400 } 1401 lif->lif_flags = lifr.lifr_flags; 1402 1403 /* 1404 * If this is initial bringup, make sure the address we're acquiring a 1405 * lease on is IFF_UP. 1406 */ 1407 if (bringup && !(lifr.lifr_flags & IFF_UP)) { 1408 /* 1409 * Start from a clean slate. 1410 */ 1411 canonize_lif(lif, B_FALSE); 1412 1413 lifr.lifr_flags |= IFF_UP; 1414 if (ioctl(v4_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1415 errmsg = "cannot bring up"; 1416 goto failure; 1417 } 1418 lif->lif_flags = lifr.lifr_flags; 1419 1420 /* 1421 * When bringing 0.0.0.0 IFF_UP, the kernel changes the 1422 * netmask to 255.0.0.0, so re-fetch our expected netmask. 1423 */ 1424 if (ioctl(v4_sock_fd, SIOCGLIFNETMASK, &lifr) == -1) { 1425 errmsg = "cannot get netmask"; 1426 goto failure; 1427 } 1428 1429 lif->lif_netmask = 1430 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr.s_addr; 1431 } 1432 1433 /* 1434 * Usually, bringing up the address we're acquiring a lease on is 1435 * sufficient to allow packets to be sent and received via the 1436 * IP_BOUND_IF we did earlier. However, if we're acquiring a lease on 1437 * an underlying IPMP interface, the group interface will be used for 1438 * sending and receiving IP packets via IP_BOUND_IF. Thus, ensure at 1439 * least one address on the group interface is IFF_UP. 1440 */ 1441 if (bringup && pif->pif_under_ipmp) { 1442 (void) strlcpy(lifr.lifr_name, pif->pif_grifname, LIFNAMSIZ); 1443 if (ioctl(v4_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { 1444 errmsg = "cannot get IPMP group interface flags"; 1445 goto failure; 1446 } 1447 1448 if (!(lifr.lifr_flags & IFF_UP)) { 1449 lifr.lifr_flags |= IFF_UP; 1450 if (ioctl(v4_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) { 1451 errmsg = "cannot bring up IPMP group interface"; 1452 goto failure; 1453 } 1454 } 1455 } 1456 1457 lif->lif_packet_id = iu_register_event(eh, lif->lif_sock_ip_fd, POLLIN, 1458 dhcp_packet_lif, lif); 1459 if (lif->lif_packet_id == -1) { 1460 errmsg = "cannot register to receive DHCP packets"; 1461 goto failure; 1462 } 1463 1464 return (B_TRUE); 1465 failure: 1466 dhcpmsg(MSG_ERR, "open_ip_lif: %s: %s", lif->lif_name, errmsg); 1467 close_ip_lif(lif); 1468 return (B_FALSE); 1469 } 1470 1471 /* 1472 * close_ip_lif(): close an IP socket for I/O on a given LIF. 1473 * 1474 * input: dhcp_lif_t *: the logical interface to operate on 1475 * output: none 1476 */ 1477 1478 void 1479 close_ip_lif(dhcp_lif_t *lif) 1480 { 1481 if (lif->lif_packet_id != -1) { 1482 (void) iu_unregister_event(eh, lif->lif_packet_id, NULL); 1483 lif->lif_packet_id = -1; 1484 } 1485 if (lif->lif_sock_ip_fd != -1) { 1486 (void) close(lif->lif_sock_ip_fd); 1487 lif->lif_sock_ip_fd = -1; 1488 } 1489 } 1490 1491 /* 1492 * lif_mark_decline(): mark a LIF as having been declined due to a duplicate 1493 * address or some other conflict. This is used in 1494 * send_declines() to report failure back to the server. 1495 * 1496 * input: dhcp_lif_t *: the logical interface to operate on 1497 * const char *: text string explaining why the address is declined 1498 * output: none 1499 */ 1500 1501 void 1502 lif_mark_decline(dhcp_lif_t *lif, const char *reason) 1503 { 1504 if (lif->lif_declined == NULL) { 1505 dhcp_lease_t *dlp; 1506 1507 lif->lif_declined = reason; 1508 if ((dlp = lif->lif_lease) != NULL) 1509 dlp->dl_smach->dsm_lif_down++; 1510 } 1511 } 1512 1513 /* 1514 * schedule_lif_timer(): schedules the LIF-related timer 1515 * 1516 * input: dhcp_lif_t *: the logical interface to operate on 1517 * dhcp_timer_t *: the timer to schedule 1518 * iu_tq_callback_t *: the callback to call upon firing 1519 * output: boolean_t: B_TRUE if the timer was scheduled successfully 1520 */ 1521 1522 boolean_t 1523 schedule_lif_timer(dhcp_lif_t *lif, dhcp_timer_t *dt, iu_tq_callback_t *expire) 1524 { 1525 /* 1526 * If there's a timer running, cancel it and release its lease 1527 * reference. 1528 */ 1529 if (dt->dt_id != -1) { 1530 if (!cancel_timer(dt)) 1531 return (B_FALSE); 1532 release_lif(lif); 1533 } 1534 1535 if (schedule_timer(dt, expire, lif)) { 1536 hold_lif(lif); 1537 return (B_TRUE); 1538 } else { 1539 dhcpmsg(MSG_WARNING, 1540 "schedule_lif_timer: cannot schedule timer"); 1541 return (B_FALSE); 1542 } 1543 } 1544 1545 /* 1546 * cancel_lif_timer(): cancels a LIF-related timer 1547 * 1548 * input: dhcp_lif_t *: the logical interface to operate on 1549 * dhcp_timer_t *: the timer to cancel 1550 * output: none 1551 */ 1552 1553 static void 1554 cancel_lif_timer(dhcp_lif_t *lif, dhcp_timer_t *dt) 1555 { 1556 if (dt->dt_id == -1) 1557 return; 1558 if (cancel_timer(dt)) { 1559 dhcpmsg(MSG_DEBUG2, 1560 "cancel_lif_timer: canceled expiry timer on %s", 1561 lif->lif_name); 1562 release_lif(lif); 1563 } else { 1564 dhcpmsg(MSG_WARNING, 1565 "cancel_lif_timer: cannot cancel timer on %s", 1566 lif->lif_name); 1567 } 1568 } 1569 1570 /* 1571 * cancel_lif_timers(): cancels the LIF-related timers 1572 * 1573 * input: dhcp_lif_t *: the logical interface to operate on 1574 * output: none 1575 */ 1576 1577 void 1578 cancel_lif_timers(dhcp_lif_t *lif) 1579 { 1580 cancel_lif_timer(lif, &lif->lif_preferred); 1581 cancel_lif_timer(lif, &lif->lif_expire); 1582 } 1583 1584 /* 1585 * get_max_mtu(): find the maximum MTU of all interfaces for I/O on common 1586 * file descriptors (v4_sock_fd and v6_sock_fd). 1587 * 1588 * input: boolean_t: B_TRUE for IPv6, B_FALSE for IPv4 1589 * output: none 1590 */ 1591 1592 uint_t 1593 get_max_mtu(boolean_t isv6) 1594 { 1595 uint_t *mtup = isv6 ? &cached_v6_max_mtu : &cached_v4_max_mtu; 1596 1597 if (*mtup == 0) { 1598 dhcp_pif_t *pif; 1599 dhcp_lif_t *lif; 1600 struct lifreq lifr; 1601 1602 /* Set an arbitrary lower bound */ 1603 *mtup = 1024; 1604 pif = isv6 ? v6root : v4root; 1605 for (; pif != NULL; pif = pif->pif_next) { 1606 for (lif = pif->pif_lifs; lif != NULL; 1607 lif = lif->lif_next) { 1608 (void) strlcpy(lifr.lifr_name, lif->lif_name, 1609 LIFNAMSIZ); 1610 if (ioctl(v4_sock_fd, SIOCGLIFMTU, &lifr) != 1611 -1 && lifr.lifr_mtu > *mtup) { 1612 *mtup = lifr.lifr_mtu; 1613 } 1614 } 1615 } 1616 } 1617 return (*mtup); 1618 } 1619 1620 /* 1621 * expired_lif_state(): summarize the state of expired LIFs on a given state 1622 * machine. 1623 * 1624 * input: dhcp_smach_t *: the state machine to scan 1625 * output: dhcp_expire_t: overall state 1626 */ 1627 1628 dhcp_expire_t 1629 expired_lif_state(dhcp_smach_t *dsmp) 1630 { 1631 dhcp_lease_t *dlp; 1632 dhcp_lif_t *lif; 1633 uint_t nlifs; 1634 uint_t numlifs; 1635 uint_t numexp; 1636 1637 numlifs = numexp = 0; 1638 for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlp->dl_next) { 1639 lif = dlp->dl_lifs; 1640 nlifs = dlp->dl_nlifs; 1641 numlifs += nlifs; 1642 for (; nlifs > 0; nlifs--, lif = lif->lif_next) { 1643 if (lif->lif_expired) 1644 numexp++; 1645 } 1646 } 1647 if (numlifs == 0) 1648 return (DHCP_EXP_NOLIFS); 1649 else if (numexp == 0) 1650 return (DHCP_EXP_NOEXP); 1651 else if (numlifs == numexp) 1652 return (DHCP_EXP_ALLEXP); 1653 else 1654 return (DHCP_EXP_SOMEEXP); 1655 } 1656 1657 /* 1658 * find_expired_lif(): find the first expired LIF on a given state machine 1659 * 1660 * input: dhcp_smach_t *: the state machine to scan 1661 * output: dhcp_lif_t *: the first expired LIF, or NULL if none. 1662 */ 1663 1664 dhcp_lif_t * 1665 find_expired_lif(dhcp_smach_t *dsmp) 1666 { 1667 dhcp_lease_t *dlp; 1668 dhcp_lif_t *lif; 1669 uint_t nlifs; 1670 1671 for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlp->dl_next) { 1672 lif = dlp->dl_lifs; 1673 nlifs = dlp->dl_nlifs; 1674 for (; nlifs > 0; nlifs--, lif = lif->lif_next) { 1675 if (lif->lif_expired) 1676 return (lif); 1677 } 1678 } 1679 return (NULL); 1680 } 1681 1682 /* 1683 * remove_v6_strays(): remove any stray interfaces marked as DHCPRUNNING. Used 1684 * only for DHCPv6. 1685 * 1686 * input: none 1687 * output: none 1688 */ 1689 1690 void 1691 remove_v6_strays(void) 1692 { 1693 struct lifnum lifn; 1694 struct lifconf lifc; 1695 struct lifreq *lifrp, *lifrmax; 1696 uint_t numifs; 1697 uint64_t flags; 1698 1699 /* 1700 * Get the approximate number of interfaces in the system. It's only 1701 * approximate because the system is dynamic -- interfaces may be 1702 * plumbed or unplumbed at any time. This is also the reason for the 1703 * "+ 10" fudge factor: we're trying to avoid unnecessary looping. 1704 */ 1705 (void) memset(&lifn, 0, sizeof (lifn)); 1706 lifn.lifn_family = AF_INET6; 1707 lifn.lifn_flags = LIFC_ALLZONES | LIFC_NOXMIT | LIFC_TEMPORARY; 1708 if (ioctl(v6_sock_fd, SIOCGLIFNUM, &lifn) == -1) { 1709 dhcpmsg(MSG_ERR, 1710 "remove_v6_strays: cannot read number of interfaces"); 1711 numifs = 10; 1712 } else { 1713 numifs = lifn.lifn_count + 10; 1714 } 1715 1716 /* 1717 * Get the interface information. We do this in a loop so that we can 1718 * recover from EINVAL from the kernel -- delivered when the buffer is 1719 * too small. 1720 */ 1721 (void) memset(&lifc, 0, sizeof (lifc)); 1722 lifc.lifc_family = AF_INET6; 1723 lifc.lifc_flags = LIFC_ALLZONES | LIFC_NOXMIT | LIFC_TEMPORARY; 1724 for (;;) { 1725 lifc.lifc_len = numifs * sizeof (*lifrp); 1726 lifrp = realloc(lifc.lifc_buf, lifc.lifc_len); 1727 if (lifrp == NULL) { 1728 dhcpmsg(MSG_ERR, 1729 "remove_v6_strays: cannot allocate memory"); 1730 free(lifc.lifc_buf); 1731 return; 1732 } 1733 lifc.lifc_buf = (caddr_t)lifrp; 1734 errno = 0; 1735 if (ioctl(v6_sock_fd, SIOCGLIFCONF, &lifc) == 0 && 1736 lifc.lifc_len < numifs * sizeof (*lifrp)) 1737 break; 1738 if (errno == 0 || errno == EINVAL) { 1739 numifs <<= 1; 1740 } else { 1741 dhcpmsg(MSG_ERR, "remove_v6_strays: SIOCGLIFCONF"); 1742 free(lifc.lifc_buf); 1743 return; 1744 } 1745 } 1746 1747 lifrmax = lifrp + lifc.lifc_len / sizeof (*lifrp); 1748 for (; lifrp < lifrmax; lifrp++) { 1749 /* 1750 * Get the interface flags; we're interested in the DHCP ones. 1751 */ 1752 if (ioctl(v6_sock_fd, SIOCGLIFFLAGS, lifrp) == -1) 1753 continue; 1754 flags = lifrp->lifr_flags; 1755 if (!(flags & IFF_DHCPRUNNING)) 1756 continue; 1757 /* 1758 * If the interface has a link-local address, then we don't 1759 * control it. Just remove the flag. 1760 */ 1761 if (ioctl(v6_sock_fd, SIOCGLIFADDR, lifrp) == -1) 1762 continue; 1763 if (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)&lifrp-> 1764 lifr_addr)->sin6_addr)) { 1765 lifrp->lifr_flags = flags & ~IFF_DHCPRUNNING; 1766 (void) ioctl(v6_sock_fd, SIOCSLIFFLAGS, lifrp); 1767 continue; 1768 } 1769 /* 1770 * All others are (or were) under our control. Clean up by 1771 * removing them. 1772 */ 1773 if (ioctl(v6_sock_fd, SIOCLIFREMOVEIF, lifrp) == 0) { 1774 dhcpmsg(MSG_DEBUG, "remove_v6_strays: removed %s", 1775 lifrp->lifr_name); 1776 } else if (errno != ENXIO) { 1777 dhcpmsg(MSG_ERR, 1778 "remove_v6_strays: SIOCLIFREMOVEIF %s", 1779 lifrp->lifr_name); 1780 } 1781 } 1782 free(lifc.lifc_buf); 1783 } 1784