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