10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51577Sseb * Common Development and Distribution License (the "License"). 61577Sseb * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 208485SPeter.Memishian@Sun.COM * 21*12016SGirish.Moodalbail@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 220Sstevel@tonic-gate * Use is subject to license terms. 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate #include "defs.h" 260Sstevel@tonic-gate #include "tables.h" 270Sstevel@tonic-gate #include <fcntl.h> 283284Sapersson #include <sys/un.h> 290Sstevel@tonic-gate 300Sstevel@tonic-gate static void initlog(void); 310Sstevel@tonic-gate static void run_timeouts(void); 320Sstevel@tonic-gate 330Sstevel@tonic-gate static void advertise(struct sockaddr_in6 *sin6, struct phyint *pi, 340Sstevel@tonic-gate boolean_t no_prefixes); 350Sstevel@tonic-gate static void solicit(struct sockaddr_in6 *sin6, struct phyint *pi); 360Sstevel@tonic-gate static void initifs(boolean_t first); 370Sstevel@tonic-gate static void check_if_removed(struct phyint *pi); 380Sstevel@tonic-gate static void loopback_ra_enqueue(struct phyint *pi, 390Sstevel@tonic-gate struct nd_router_advert *ra, int len); 400Sstevel@tonic-gate static void loopback_ra_dequeue(void); 410Sstevel@tonic-gate static void check_daemonize(void); 420Sstevel@tonic-gate 430Sstevel@tonic-gate struct in6_addr all_nodes_mcast = { { 0xff, 0x2, 0x0, 0x0, 440Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 450Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 460Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } }; 470Sstevel@tonic-gate 480Sstevel@tonic-gate struct in6_addr all_routers_mcast = { { 0xff, 0x2, 0x0, 0x0, 490Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 500Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 510Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } }; 520Sstevel@tonic-gate 530Sstevel@tonic-gate static struct sockaddr_in6 v6allnodes = { AF_INET6, 0, 0, 540Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0, 550Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 560Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 570Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } }; 580Sstevel@tonic-gate 590Sstevel@tonic-gate static struct sockaddr_in6 v6allrouters = { AF_INET6, 0, 0, 600Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0, 610Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 620Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 630Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } }; 640Sstevel@tonic-gate 650Sstevel@tonic-gate static char **argv0; /* Saved for re-exec on SIGHUP */ 660Sstevel@tonic-gate 670Sstevel@tonic-gate static uint64_t packet[(IP_MAXPACKET + 1)/8]; 680Sstevel@tonic-gate 690Sstevel@tonic-gate static int show_ifs = 0; 700Sstevel@tonic-gate static boolean_t already_daemonized = _B_FALSE; 710Sstevel@tonic-gate int debug = 0; 720Sstevel@tonic-gate int no_loopback = 0; /* Do not send RA packets to ourselves */ 730Sstevel@tonic-gate 740Sstevel@tonic-gate /* 750Sstevel@tonic-gate * Size of routing socket message used by in.ndpd which includes the header, 760Sstevel@tonic-gate * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6) 770Sstevel@tonic-gate * plus space for the RTA_IFP (a sockaddr_dl). 780Sstevel@tonic-gate */ 790Sstevel@tonic-gate #define NDP_RTM_MSGLEN sizeof (struct rt_msghdr) + \ 800Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 810Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 820Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 830Sstevel@tonic-gate sizeof (struct sockaddr_dl) 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * These are referenced externally in tables.c in order to fill in the 870Sstevel@tonic-gate * dynamic portions of the routing socket message and then to send the message 880Sstevel@tonic-gate * itself. 890Sstevel@tonic-gate */ 900Sstevel@tonic-gate int rtsock = -1; /* Routing socket */ 910Sstevel@tonic-gate struct rt_msghdr *rt_msg; /* Routing socket message */ 920Sstevel@tonic-gate struct sockaddr_in6 *rta_gateway; /* RTA_GATEWAY sockaddr */ 930Sstevel@tonic-gate struct sockaddr_dl *rta_ifp; /* RTA_IFP sockaddr */ 94*12016SGirish.Moodalbail@Sun.COM 95*12016SGirish.Moodalbail@Sun.COM /* 96*12016SGirish.Moodalbail@Sun.COM * These sockets are used internally in this file. 97*12016SGirish.Moodalbail@Sun.COM */ 98*12016SGirish.Moodalbail@Sun.COM static int mibsock = -1; /* mib request socket */ 99*12016SGirish.Moodalbail@Sun.COM static int cmdsock = -1; /* command socket */ 100*12016SGirish.Moodalbail@Sun.COM 101*12016SGirish.Moodalbail@Sun.COM static int ndpd_setup_cmd_listener(void); 102*12016SGirish.Moodalbail@Sun.COM static void ndpd_cmd_handler(int); 103*12016SGirish.Moodalbail@Sun.COM static int ndpd_process_cmd(int, ipadm_ndpd_msg_t *); 104*12016SGirish.Moodalbail@Sun.COM static int ndpd_send_error(int, int); 105*12016SGirish.Moodalbail@Sun.COM static int ndpd_set_autoconf(const char *, boolean_t); 106*12016SGirish.Moodalbail@Sun.COM static int ndpd_create_addrs(const char *, struct sockaddr_in6, int, 107*12016SGirish.Moodalbail@Sun.COM boolean_t, boolean_t, char *); 108*12016SGirish.Moodalbail@Sun.COM static int ndpd_delete_addrs(const char *); 109*12016SGirish.Moodalbail@Sun.COM static int phyint_check_ipadm_intfid(struct phyint *); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * Return the current time in milliseconds truncated to 1130Sstevel@tonic-gate * fit in an integer. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate uint_t 1160Sstevel@tonic-gate getcurrenttime(void) 1170Sstevel@tonic-gate { 1180Sstevel@tonic-gate struct timeval tp; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if (gettimeofday(&tp, NULL) < 0) { 1210Sstevel@tonic-gate logperror("getcurrenttime: gettimeofday failed"); 1220Sstevel@tonic-gate exit(1); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate return (tp.tv_sec * 1000 + tp.tv_usec / 1000); 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * Output a preformated packet from the packet[] buffer. 1290Sstevel@tonic-gate */ 1300Sstevel@tonic-gate static void 1310Sstevel@tonic-gate sendpacket(struct sockaddr_in6 *sin6, int sock, int size, int flags) 1320Sstevel@tonic-gate { 1330Sstevel@tonic-gate int cc; 1340Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate cc = sendto(sock, (char *)packet, size, flags, 1378485SPeter.Memishian@Sun.COM (struct sockaddr *)sin6, sizeof (*sin6)); 1380Sstevel@tonic-gate if (cc < 0 || cc != size) { 1390Sstevel@tonic-gate if (cc < 0) { 1400Sstevel@tonic-gate logperror("sendpacket: sendto"); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate logmsg(LOG_ERR, "sendpacket: wrote %s %d chars, ret=%d\n", 1430Sstevel@tonic-gate inet_ntop(sin6->sin6_family, 1440Sstevel@tonic-gate (void *)&sin6->sin6_addr, 1450Sstevel@tonic-gate abuf, sizeof (abuf)), 1460Sstevel@tonic-gate size, cc); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1508485SPeter.Memishian@Sun.COM /* 1518485SPeter.Memishian@Sun.COM * If possible, place an ND_OPT_SOURCE_LINKADDR option at `optp'. 1528485SPeter.Memishian@Sun.COM * Return the number of bytes placed in the option. 1538485SPeter.Memishian@Sun.COM */ 1548485SPeter.Memishian@Sun.COM static uint_t 1558485SPeter.Memishian@Sun.COM add_opt_lla(struct phyint *pi, struct nd_opt_lla *optp) 1568485SPeter.Memishian@Sun.COM { 1578485SPeter.Memishian@Sun.COM uint_t optlen; 1588485SPeter.Memishian@Sun.COM uint_t hwaddrlen; 1598485SPeter.Memishian@Sun.COM struct lifreq lifr; 1608485SPeter.Memishian@Sun.COM 1618485SPeter.Memishian@Sun.COM /* If this phyint doesn't have a link-layer address, bail */ 1628485SPeter.Memishian@Sun.COM if (phyint_get_lla(pi, &lifr) == -1) 1638485SPeter.Memishian@Sun.COM return (0); 1648485SPeter.Memishian@Sun.COM 1658485SPeter.Memishian@Sun.COM hwaddrlen = lifr.lifr_nd.lnr_hdw_len; 1668485SPeter.Memishian@Sun.COM /* roundup to multiple of 8 and make padding zero */ 1678485SPeter.Memishian@Sun.COM optlen = ((sizeof (struct nd_opt_hdr) + hwaddrlen + 7) / 8) * 8; 1688485SPeter.Memishian@Sun.COM bzero(optp, optlen); 1698485SPeter.Memishian@Sun.COM optp->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR; 1708485SPeter.Memishian@Sun.COM optp->nd_opt_lla_len = optlen / 8; 1718485SPeter.Memishian@Sun.COM bcopy(lifr.lifr_nd.lnr_hdw_addr, optp->nd_opt_lla_hdw_addr, hwaddrlen); 1728485SPeter.Memishian@Sun.COM 1738485SPeter.Memishian@Sun.COM return (optlen); 1748485SPeter.Memishian@Sun.COM } 1758485SPeter.Memishian@Sun.COM 1760Sstevel@tonic-gate /* Send a Router Solicitation */ 1770Sstevel@tonic-gate static void 1780Sstevel@tonic-gate solicit(struct sockaddr_in6 *sin6, struct phyint *pi) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate int packetlen = 0; 1810Sstevel@tonic-gate struct nd_router_solicit *rs = (struct nd_router_solicit *)packet; 1820Sstevel@tonic-gate char *pptr = (char *)packet; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate rs->nd_rs_type = ND_ROUTER_SOLICIT; 1850Sstevel@tonic-gate rs->nd_rs_code = 0; 1860Sstevel@tonic-gate rs->nd_rs_cksum = htons(0); 1870Sstevel@tonic-gate rs->nd_rs_reserved = htonl(0); 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate packetlen += sizeof (*rs); 1900Sstevel@tonic-gate pptr += sizeof (*rs); 1910Sstevel@tonic-gate 1928485SPeter.Memishian@Sun.COM /* add options */ 1938485SPeter.Memishian@Sun.COM packetlen += add_opt_lla(pi, (struct nd_opt_lla *)pptr); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate if (debug & D_PKTOUT) { 1960Sstevel@tonic-gate print_route_sol("Sending solicitation to ", pi, rs, packetlen, 1970Sstevel@tonic-gate sin6); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * Send a (set of) Router Advertisements and feed them back to ourselves 2040Sstevel@tonic-gate * for processing. Unless no_prefixes is set all prefixes are included. 2050Sstevel@tonic-gate * If there are too many prefix options to fit in one packet multiple 2060Sstevel@tonic-gate * packets will be sent - each containing a subset of the prefix options. 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate static void 2090Sstevel@tonic-gate advertise(struct sockaddr_in6 *sin6, struct phyint *pi, boolean_t no_prefixes) 2100Sstevel@tonic-gate { 2110Sstevel@tonic-gate struct nd_opt_prefix_info *po; 2120Sstevel@tonic-gate char *pptr = (char *)packet; 2130Sstevel@tonic-gate struct nd_router_advert *ra; 2140Sstevel@tonic-gate struct adv_prefix *adv_pr; 2150Sstevel@tonic-gate int packetlen = 0; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate ra = (struct nd_router_advert *)pptr; 2180Sstevel@tonic-gate ra->nd_ra_type = ND_ROUTER_ADVERT; 2190Sstevel@tonic-gate ra->nd_ra_code = 0; 2200Sstevel@tonic-gate ra->nd_ra_cksum = htons(0); 2210Sstevel@tonic-gate ra->nd_ra_curhoplimit = pi->pi_AdvCurHopLimit; 2220Sstevel@tonic-gate ra->nd_ra_flags_reserved = 0; 2230Sstevel@tonic-gate if (pi->pi_AdvManagedFlag) 2240Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; 2250Sstevel@tonic-gate if (pi->pi_AdvOtherConfigFlag) 2260Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) 2290Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(0); 2300Sstevel@tonic-gate else 2310Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(pi->pi_AdvDefaultLifetime); 2320Sstevel@tonic-gate ra->nd_ra_reachable = htonl(pi->pi_AdvReachableTime); 2330Sstevel@tonic-gate ra->nd_ra_retransmit = htonl(pi->pi_AdvRetransTimer); 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate packetlen = sizeof (*ra); 2360Sstevel@tonic-gate pptr += sizeof (*ra); 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) { 2390Sstevel@tonic-gate if (debug & D_PKTOUT) { 2400Sstevel@tonic-gate print_route_adv("Sending advert (FINAL) to ", pi, 2410Sstevel@tonic-gate ra, packetlen, sin6); 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2440Sstevel@tonic-gate /* Feed packet back in for router operation */ 2450Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2460Sstevel@tonic-gate return; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2498485SPeter.Memishian@Sun.COM /* add options */ 2508485SPeter.Memishian@Sun.COM packetlen += add_opt_lla(pi, (struct nd_opt_lla *)pptr); 2518485SPeter.Memishian@Sun.COM pptr = (char *)packet + packetlen; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate if (pi->pi_AdvLinkMTU != 0) { 2540Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)pptr; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate mo->nd_opt_mtu_type = ND_OPT_MTU; 2570Sstevel@tonic-gate mo->nd_opt_mtu_len = sizeof (struct nd_opt_mtu) / 8; 2580Sstevel@tonic-gate mo->nd_opt_mtu_reserved = 0; 2590Sstevel@tonic-gate mo->nd_opt_mtu_mtu = htonl(pi->pi_AdvLinkMTU); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate packetlen += sizeof (struct nd_opt_mtu); 2620Sstevel@tonic-gate pptr += sizeof (struct nd_opt_mtu); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate if (no_prefixes) { 2660Sstevel@tonic-gate if (debug & D_PKTOUT) { 2670Sstevel@tonic-gate print_route_adv("Sending advert to ", pi, 2680Sstevel@tonic-gate ra, packetlen, sin6); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2710Sstevel@tonic-gate /* Feed packet back in for router operation */ 2720Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2730Sstevel@tonic-gate return; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr; 2770Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 2780Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 2790Sstevel@tonic-gate if (!adv_pr->adv_pr_AdvOnLinkFlag && 2800Sstevel@tonic-gate !adv_pr->adv_pr_AdvAutonomousFlag) { 2810Sstevel@tonic-gate continue; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate /* 2850Sstevel@tonic-gate * If the prefix doesn't fit in packet send 2860Sstevel@tonic-gate * what we have so far and start with new packet. 2870Sstevel@tonic-gate */ 2880Sstevel@tonic-gate if (packetlen + sizeof (*po) > 2890Sstevel@tonic-gate pi->pi_LinkMTU - sizeof (struct ip6_hdr)) { 2900Sstevel@tonic-gate if (debug & D_PKTOUT) { 2910Sstevel@tonic-gate print_route_adv("Sending advert " 2920Sstevel@tonic-gate "(FRAG) to ", 2930Sstevel@tonic-gate pi, ra, packetlen, sin6); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2960Sstevel@tonic-gate /* Feed packet back in for router operation */ 2970Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2980Sstevel@tonic-gate packetlen = sizeof (*ra); 2990Sstevel@tonic-gate pptr = (char *)packet + sizeof (*ra); 3000Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr; 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate po->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 3030Sstevel@tonic-gate po->nd_opt_pi_len = sizeof (*po)/8; 3040Sstevel@tonic-gate po->nd_opt_pi_flags_reserved = 0; 3050Sstevel@tonic-gate if (adv_pr->adv_pr_AdvOnLinkFlag) { 3060Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |= 3070Sstevel@tonic-gate ND_OPT_PI_FLAG_ONLINK; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate if (adv_pr->adv_pr_AdvAutonomousFlag) { 3100Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |= 3110Sstevel@tonic-gate ND_OPT_PI_FLAG_AUTO; 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate po->nd_opt_pi_prefix_len = adv_pr->adv_pr_prefix_len; 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * If both Adv*Expiration and Adv*Lifetime are 3160Sstevel@tonic-gate * set we prefer the former and make the lifetime 3170Sstevel@tonic-gate * decrement in real time. 3180Sstevel@tonic-gate */ 3190Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 3200Sstevel@tonic-gate po->nd_opt_pi_valid_time = 3210Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidExpiration); 3220Sstevel@tonic-gate } else { 3230Sstevel@tonic-gate po->nd_opt_pi_valid_time = 3240Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidLifetime); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 3270Sstevel@tonic-gate po->nd_opt_pi_preferred_time = 3280Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredExpiration); 3290Sstevel@tonic-gate } else { 3300Sstevel@tonic-gate po->nd_opt_pi_preferred_time = 3310Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredLifetime); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate po->nd_opt_pi_reserved2 = htonl(0); 3340Sstevel@tonic-gate po->nd_opt_pi_prefix = adv_pr->adv_pr_prefix; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate po++; 3370Sstevel@tonic-gate packetlen += sizeof (*po); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate if (debug & D_PKTOUT) { 3400Sstevel@tonic-gate print_route_adv("Sending advert to ", pi, 3410Sstevel@tonic-gate ra, packetlen, sin6); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 3440Sstevel@tonic-gate /* Feed packet back in for router operation */ 3450Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate /* Poll support */ 3490Sstevel@tonic-gate static int pollfd_num = 0; /* Allocated and initialized */ 3500Sstevel@tonic-gate static struct pollfd *pollfds = NULL; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Add fd to the set being polled. Returns 0 if ok; -1 if failed. 3540Sstevel@tonic-gate */ 3550Sstevel@tonic-gate int 3560Sstevel@tonic-gate poll_add(int fd) 3570Sstevel@tonic-gate { 3580Sstevel@tonic-gate int i; 3590Sstevel@tonic-gate int new_num; 3600Sstevel@tonic-gate struct pollfd *newfds; 3613284Sapersson 3620Sstevel@tonic-gate /* Check if already present */ 3630Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3640Sstevel@tonic-gate if (pollfds[i].fd == fd) 3650Sstevel@tonic-gate return (0); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate /* Check for empty spot already present */ 3680Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3690Sstevel@tonic-gate if (pollfds[i].fd == -1) { 3700Sstevel@tonic-gate pollfds[i].fd = fd; 3710Sstevel@tonic-gate return (0); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate /* Allocate space for 32 more fds and initialize to -1 */ 3760Sstevel@tonic-gate new_num = pollfd_num + 32; 3770Sstevel@tonic-gate newfds = realloc(pollfds, new_num * sizeof (struct pollfd)); 3780Sstevel@tonic-gate if (newfds == NULL) { 379*12016SGirish.Moodalbail@Sun.COM logperror("realloc"); 3800Sstevel@tonic-gate return (-1); 3810Sstevel@tonic-gate } 3823284Sapersson 3833284Sapersson newfds[pollfd_num].fd = fd; 3843284Sapersson newfds[pollfd_num++].events = POLLIN; 3853284Sapersson 3860Sstevel@tonic-gate for (i = pollfd_num; i < new_num; i++) { 3870Sstevel@tonic-gate newfds[i].fd = -1; 3880Sstevel@tonic-gate newfds[i].events = POLLIN; 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate pollfd_num = new_num; 3910Sstevel@tonic-gate pollfds = newfds; 3923284Sapersson return (0); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate * Remove fd from the set being polled. Returns 0 if ok; -1 if failed. 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate int 3990Sstevel@tonic-gate poll_remove(int fd) 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate int i; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* Check if already present */ 4040Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 4050Sstevel@tonic-gate if (pollfds[i].fd == fd) { 4060Sstevel@tonic-gate pollfds[i].fd = -1; 4070Sstevel@tonic-gate return (0); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate return (-1); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate /* 4140Sstevel@tonic-gate * Extract information about the ifname (either a physical interface and 4150Sstevel@tonic-gate * the ":0" logical interface or just a logical interface). 4160Sstevel@tonic-gate * If the interface (still) exists in kernel set pr_in_use 4170Sstevel@tonic-gate * for caller to be able to detect interfaces that are removed. 4180Sstevel@tonic-gate * Starts sending advertisements/solicitations when new physical interfaces 4190Sstevel@tonic-gate * are detected. 4200Sstevel@tonic-gate */ 4210Sstevel@tonic-gate static void 4220Sstevel@tonic-gate if_process(int s, char *ifname, boolean_t first) 4230Sstevel@tonic-gate { 4240Sstevel@tonic-gate struct lifreq lifr; 4250Sstevel@tonic-gate struct phyint *pi; 4260Sstevel@tonic-gate struct prefix *pr; 4270Sstevel@tonic-gate char *cp; 4280Sstevel@tonic-gate char phyintname[LIFNAMSIZ + 1]; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate if (debug & D_IFSCAN) 4310Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process(%s)\n", ifname); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 4340Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 4350Sstevel@tonic-gate if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 4360Sstevel@tonic-gate if (errno == ENXIO) { 4370Sstevel@tonic-gate /* 4380Sstevel@tonic-gate * Interface has disappeared 4390Sstevel@tonic-gate */ 4400Sstevel@tonic-gate return; 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate logperror("if_process: ioctl (get interface flags)"); 4430Sstevel@tonic-gate return; 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* 44711076SCathy.Zhou@Sun.COM * Ignore loopback, point-to-multipoint and VRRP interfaces. 44811076SCathy.Zhou@Sun.COM * The IP addresses over VRRP interfaces cannot be auto-configured. 4490Sstevel@tonic-gate * Point-to-point interfaces always have IFF_MULTICAST set. 4500Sstevel@tonic-gate */ 4510Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_MULTICAST) || 45211076SCathy.Zhou@Sun.COM (lifr.lifr_flags & (IFF_LOOPBACK|IFF_VRRP))) { 4530Sstevel@tonic-gate return; 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_IPV6)) 4570Sstevel@tonic-gate return; 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate (void) strncpy(phyintname, ifname, sizeof (phyintname)); 4600Sstevel@tonic-gate phyintname[sizeof (phyintname) - 1] = '\0'; 4610Sstevel@tonic-gate if ((cp = strchr(phyintname, IF_SEPARATOR)) != NULL) { 4620Sstevel@tonic-gate *cp = '\0'; 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate pi = phyint_lookup(phyintname); 4660Sstevel@tonic-gate if (pi == NULL) { 4670Sstevel@tonic-gate pi = phyint_create(phyintname); 4680Sstevel@tonic-gate if (pi == NULL) { 4690Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n"); 4700Sstevel@tonic-gate return; 4710Sstevel@tonic-gate } 472*12016SGirish.Moodalbail@Sun.COM /* 473*12016SGirish.Moodalbail@Sun.COM * if in.ndpd is restarted, check with ipmgmtd if there is any 474*12016SGirish.Moodalbail@Sun.COM * interface id to be configured for this interface. 475*12016SGirish.Moodalbail@Sun.COM */ 476*12016SGirish.Moodalbail@Sun.COM if (first) { 477*12016SGirish.Moodalbail@Sun.COM if (phyint_check_ipadm_intfid(pi) == -1) 478*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "Could not get ipadm info\n"); 479*12016SGirish.Moodalbail@Sun.COM } 480*12016SGirish.Moodalbail@Sun.COM } else { 481*12016SGirish.Moodalbail@Sun.COM /* 482*12016SGirish.Moodalbail@Sun.COM * if the phyint already exists, synchronize it with 483*12016SGirish.Moodalbail@Sun.COM * the kernel state. For a newly created phyint, phyint_create 484*12016SGirish.Moodalbail@Sun.COM * calls phyint_init_from_k(). 485*12016SGirish.Moodalbail@Sun.COM */ 486*12016SGirish.Moodalbail@Sun.COM (void) phyint_init_from_k(pi); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate if (pi->pi_sock == -1 && !(pi->pi_kernel_state & PI_PRESENT)) { 4890Sstevel@tonic-gate /* Interface is not yet present */ 4900Sstevel@tonic-gate if (debug & D_PHYINT) { 4910Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process: interface not yet " 4920Sstevel@tonic-gate "present %s\n", pi->pi_name); 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate return; 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate if (pi->pi_sock != -1) { 4980Sstevel@tonic-gate if (poll_add(pi->pi_sock) == -1) { 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * reset state. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate phyint_cleanup(pi); 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Check if IFF_ROUTER has been turned off in kernel in which 5080Sstevel@tonic-gate * case we have to turn off AdvSendAdvertisements. 5090Sstevel@tonic-gate * The kernel will automatically turn off IFF_ROUTER if 5100Sstevel@tonic-gate * ip6_forwarding is turned off. 5110Sstevel@tonic-gate * Note that we do not switch back should IFF_ROUTER be turned on. 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate if (!first && 5140Sstevel@tonic-gate pi->pi_AdvSendAdvertisements && !(pi->pi_flags & IFF_ROUTER)) { 5150Sstevel@tonic-gate logmsg(LOG_INFO, "No longer a router on %s\n", pi->pi_name); 5160Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate pi->pi_AdvSendAdvertisements = 0; 5190Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT; 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate /* 5230Sstevel@tonic-gate * Send advertisments and solicitation only if the interface is 5240Sstevel@tonic-gate * present in the kernel. 5250Sstevel@tonic-gate */ 5260Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 5290Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 5300Sstevel@tonic-gate check_to_advertise(pi, START_INIT_ADV); 5310Sstevel@tonic-gate } else { 5320Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT) 5330Sstevel@tonic-gate check_to_solicit(pi, START_INIT_SOLICIT); 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate /* 5380Sstevel@tonic-gate * Track static kernel prefixes to prevent in.ndpd from clobbering 5390Sstevel@tonic-gate * them by creating a struct prefix for each prefix detected in the 5400Sstevel@tonic-gate * kernel. 5410Sstevel@tonic-gate */ 5420Sstevel@tonic-gate pr = prefix_lookup_name(pi, ifname); 5430Sstevel@tonic-gate if (pr == NULL) { 5440Sstevel@tonic-gate pr = prefix_create_name(pi, ifname); 5450Sstevel@tonic-gate if (pr == NULL) { 5460Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n"); 5470Sstevel@tonic-gate return; 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate if (prefix_init_from_k(pr) == -1) { 5500Sstevel@tonic-gate prefix_delete(pr); 5510Sstevel@tonic-gate return; 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate /* Detect prefixes which are removed */ 5550Sstevel@tonic-gate if (pr->pr_kernel_state != 0) 5560Sstevel@tonic-gate pr->pr_in_use = _B_TRUE; 5572546Scarlsonj 5582546Scarlsonj if ((lifr.lifr_flags & IFF_DUPLICATE) && 5593431Scarlsonj !(lifr.lifr_flags & IFF_DHCPRUNNING) && 5602546Scarlsonj (pr->pr_flags & IFF_TEMPORARY)) { 5612546Scarlsonj in6_addr_t *token; 5622546Scarlsonj int i; 5632546Scarlsonj char abuf[INET6_ADDRSTRLEN]; 5642546Scarlsonj 5652546Scarlsonj if (++pr->pr_attempts >= MAX_DAD_FAILURES) { 5662546Scarlsonj logmsg(LOG_ERR, "%s: token %s is duplicate after %d " 5672546Scarlsonj "attempts; disabling temporary addresses on %s", 5682546Scarlsonj pr->pr_name, inet_ntop(AF_INET6, 5692546Scarlsonj (void *)&pi->pi_tmp_token, abuf, sizeof (abuf)), 5702546Scarlsonj pr->pr_attempts, pi->pi_name); 5712546Scarlsonj pi->pi_TmpAddrsEnabled = 0; 5722546Scarlsonj tmptoken_delete(pi); 5732546Scarlsonj prefix_delete(pr); 5742546Scarlsonj return; 5752546Scarlsonj } 5762546Scarlsonj logmsg(LOG_WARNING, "%s: token %s is duplicate; trying again", 5772546Scarlsonj pr->pr_name, inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token, 5782546Scarlsonj abuf, sizeof (abuf))); 5792546Scarlsonj if (!tmptoken_create(pi)) { 5802546Scarlsonj prefix_delete(pr); 5812546Scarlsonj return; 5822546Scarlsonj } 5832546Scarlsonj token = &pi->pi_tmp_token; 5842546Scarlsonj for (i = 0; i < 16; i++) { 5852546Scarlsonj /* 5862546Scarlsonj * prefix_create ensures that pr_prefix has all-zero 5872546Scarlsonj * bits after prefixlen. 5882546Scarlsonj */ 5892546Scarlsonj pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] | 5902546Scarlsonj token->s6_addr[i]; 5912546Scarlsonj } 5922546Scarlsonj if (prefix_lookup_addr_match(pr) != NULL) { 5932546Scarlsonj prefix_delete(pr); 5942546Scarlsonj return; 5952546Scarlsonj } 5962546Scarlsonj pr->pr_CreateTime = getcurrenttime() / MILLISEC; 5972546Scarlsonj /* 5982546Scarlsonj * We've got a new token. Clearing PR_AUTO causes 5992546Scarlsonj * prefix_update_k to bring the interface up and set the 6002546Scarlsonj * address. 6012546Scarlsonj */ 6022546Scarlsonj pr->pr_kernel_state &= ~PR_AUTO; 6032546Scarlsonj prefix_update_k(pr); 6042546Scarlsonj } 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate static int ifsock = -1; 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate /* 6100Sstevel@tonic-gate * Scan all interfaces to detect changes as well as new and deleted intefaces 6110Sstevel@tonic-gate * 'first' is set for the initial call only. Do not effect anything. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate static void 6140Sstevel@tonic-gate initifs(boolean_t first) 6150Sstevel@tonic-gate { 6160Sstevel@tonic-gate char *buf; 6170Sstevel@tonic-gate int bufsize; 6180Sstevel@tonic-gate int numifs; 6190Sstevel@tonic-gate int n; 6200Sstevel@tonic-gate struct lifnum lifn; 6210Sstevel@tonic-gate struct lifconf lifc; 6220Sstevel@tonic-gate struct lifreq *lifr; 6230Sstevel@tonic-gate struct phyint *pi; 6240Sstevel@tonic-gate struct phyint *next_pi; 6250Sstevel@tonic-gate struct prefix *pr; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate if (debug & D_IFSCAN) 6280Sstevel@tonic-gate logmsg(LOG_DEBUG, "Reading interface configuration\n"); 6290Sstevel@tonic-gate if (ifsock < 0) { 6300Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 6310Sstevel@tonic-gate if (ifsock < 0) { 6320Sstevel@tonic-gate logperror("initifs: socket"); 6330Sstevel@tonic-gate return; 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate lifn.lifn_family = AF_INET6; 6370Sstevel@tonic-gate lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 6380Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFNUM, (char *)&lifn) < 0) { 6390Sstevel@tonic-gate logperror("initifs: ioctl (get interface numbers)"); 6400Sstevel@tonic-gate return; 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate numifs = lifn.lifn_count; 6430Sstevel@tonic-gate bufsize = numifs * sizeof (struct lifreq); 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate buf = (char *)malloc(bufsize); 6460Sstevel@tonic-gate if (buf == NULL) { 6470Sstevel@tonic-gate logmsg(LOG_ERR, "initifs: out of memory\n"); 6480Sstevel@tonic-gate return; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 6530Sstevel@tonic-gate * which have disappeared from the kernel. 6540Sstevel@tonic-gate * if_process will set pr_in_use when it finds the interface 6550Sstevel@tonic-gate * in the kernel. 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 6580Sstevel@tonic-gate /* 6590Sstevel@tonic-gate * Before re-examining the state of the interfaces, 6600Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 6610Sstevel@tonic-gate */ 6620Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 6630Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 6640Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate lifc.lifc_family = AF_INET6; 6690Sstevel@tonic-gate lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 6700Sstevel@tonic-gate lifc.lifc_len = bufsize; 6710Sstevel@tonic-gate lifc.lifc_buf = buf; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFCONF, (char *)&lifc) < 0) { 6740Sstevel@tonic-gate logperror("initifs: ioctl (get interface configuration)"); 6750Sstevel@tonic-gate free(buf); 6760Sstevel@tonic-gate return; 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate lifr = (struct lifreq *)lifc.lifc_req; 6800Sstevel@tonic-gate for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifr++) 6810Sstevel@tonic-gate if_process(ifsock, lifr->lifr_name, first); 6820Sstevel@tonic-gate free(buf); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate /* 6850Sstevel@tonic-gate * Detect phyints that have been removed from the kernel. 6860Sstevel@tonic-gate * Since we can't recreate it here (would require ifconfig plumb 6870Sstevel@tonic-gate * logic) we just terminate use of that phyint. 6880Sstevel@tonic-gate */ 6890Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 6900Sstevel@tonic-gate next_pi = pi->pi_next; 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * If interface (still) exists in kernel, set 6930Sstevel@tonic-gate * pi_state to indicate that. 6940Sstevel@tonic-gate */ 6950Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 6960Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate check_if_removed(pi); 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate if (show_ifs) 7020Sstevel@tonic-gate phyint_print_all(); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate /* 7070Sstevel@tonic-gate * Router advertisement state machine. Used for everything but timer 7080Sstevel@tonic-gate * events which use advertise_event directly. 7090Sstevel@tonic-gate */ 7100Sstevel@tonic-gate void 7110Sstevel@tonic-gate check_to_advertise(struct phyint *pi, enum adv_events event) 7120Sstevel@tonic-gate { 7130Sstevel@tonic-gate uint_t delay; 7140Sstevel@tonic-gate enum adv_states old_state = pi->pi_adv_state; 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate if (debug & D_STATE) { 7170Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d\n", 7180Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate delay = advertise_event(pi, event, 0); 7210Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 7220Sstevel@tonic-gate /* Make sure the global next event is updated */ 7230Sstevel@tonic-gate timer_schedule(delay); 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (debug & D_STATE) { 7270Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d -> %d\n", 7280Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 7290Sstevel@tonic-gate (int)pi->pi_adv_state); 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate /* 7340Sstevel@tonic-gate * Router advertisement state machine. 7350Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 7360Sstevel@tonic-gate * if never). 7370Sstevel@tonic-gate * For the ADV_TIMER event the caller passes in the number of milliseconds 7380Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 7390Sstevel@tonic-gate */ 7400Sstevel@tonic-gate uint_t 7410Sstevel@tonic-gate advertise_event(struct phyint *pi, enum adv_events event, uint_t elapsed) 7420Sstevel@tonic-gate { 7430Sstevel@tonic-gate uint_t delay; 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate if (debug & D_STATE) { 7460Sstevel@tonic-gate logmsg(LOG_DEBUG, "advertise_event(%s, %d, %d) state %d\n", 7470Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_adv_state); 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate check_daemonize(); 7500Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) 7510Sstevel@tonic-gate return (TIMER_INFINITY); 7520Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 7530Sstevel@tonic-gate if (debug & D_PKTOUT) { 7540Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RA packet on %s " 7550Sstevel@tonic-gate "(no route exchange on interface)\n", 7560Sstevel@tonic-gate pi->pi_name); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate return (TIMER_INFINITY); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate switch (event) { 7620Sstevel@tonic-gate case ADV_OFF: 7630Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 7640Sstevel@tonic-gate return (TIMER_INFINITY); 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate case START_INIT_ADV: 7670Sstevel@tonic-gate if (pi->pi_adv_state == INIT_ADV) 7680Sstevel@tonic-gate return (pi->pi_adv_time_left); 7690Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_INITIAL_RTR_ADVERTISEMENTS; 7700Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7710Sstevel@tonic-gate pi->pi_adv_state = INIT_ADV; 7720Sstevel@tonic-gate break; /* send advertisement */ 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate case START_FINAL_ADV: 7750Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7760Sstevel@tonic-gate return (TIMER_INFINITY); 7770Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) 7780Sstevel@tonic-gate return (pi->pi_adv_time_left); 7790Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_FINAL_RTR_ADVERTISEMENTS; 7800Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7810Sstevel@tonic-gate pi->pi_adv_state = FINAL_ADV; 7820Sstevel@tonic-gate break; /* send advertisement */ 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate case RECEIVED_SOLICIT: 7850Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7860Sstevel@tonic-gate return (TIMER_INFINITY); 7870Sstevel@tonic-gate if (pi->pi_adv_state == SOLICIT_ADV) { 7880Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 7890Sstevel@tonic-gate return (pi->pi_adv_time_left); 7900Sstevel@tonic-gate break; 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate delay = GET_RANDOM(0, ND_MAX_RA_DELAY_TIME); 7930Sstevel@tonic-gate if (delay < pi->pi_adv_time_left) 7940Sstevel@tonic-gate pi->pi_adv_time_left = delay; 7950Sstevel@tonic-gate if (pi->pi_adv_time_since_sent < ND_MIN_DELAY_BETWEEN_RAS) { 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Send an advertisement (ND_MIN_DELAY_BETWEEN_RAS 7980Sstevel@tonic-gate * plus random delay) after the previous 7990Sstevel@tonic-gate * advertisement was sent. 8000Sstevel@tonic-gate */ 8010Sstevel@tonic-gate pi->pi_adv_time_left = delay + 8020Sstevel@tonic-gate ND_MIN_DELAY_BETWEEN_RAS - 8030Sstevel@tonic-gate pi->pi_adv_time_since_sent; 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate pi->pi_adv_state = SOLICIT_ADV; 8060Sstevel@tonic-gate break; 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate case ADV_TIMER: 8090Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 8100Sstevel@tonic-gate return (TIMER_INFINITY); 8110Sstevel@tonic-gate /* Decrease time left */ 8120Sstevel@tonic-gate if (pi->pi_adv_time_left >= elapsed) 8130Sstevel@tonic-gate pi->pi_adv_time_left -= elapsed; 8140Sstevel@tonic-gate else 8150Sstevel@tonic-gate pi->pi_adv_time_left = 0; 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate /* Increase time since last advertisement was sent */ 8180Sstevel@tonic-gate pi->pi_adv_time_since_sent += elapsed; 8190Sstevel@tonic-gate break; 8200Sstevel@tonic-gate default: 8210Sstevel@tonic-gate logmsg(LOG_ERR, "advertise_event: Unknown event %d\n", 8220Sstevel@tonic-gate (int)event); 8230Sstevel@tonic-gate return (TIMER_INFINITY); 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 8270Sstevel@tonic-gate return (pi->pi_adv_time_left); 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /* Send advertisement and calculate next time to send */ 8300Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) { 8310Sstevel@tonic-gate /* Omit the prefixes */ 8320Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_TRUE); 8330Sstevel@tonic-gate } else { 8340Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_FALSE); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate pi->pi_adv_time_since_sent = 0; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate switch (pi->pi_adv_state) { 8390Sstevel@tonic-gate case SOLICIT_ADV: 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * The solicited advertisement has been sent. 8420Sstevel@tonic-gate * Revert to periodic advertisements. 8430Sstevel@tonic-gate */ 8440Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 8450Sstevel@tonic-gate /* FALLTHRU */ 8460Sstevel@tonic-gate case REG_ADV: 8470Sstevel@tonic-gate pi->pi_adv_time_left = 8480Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8490Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8500Sstevel@tonic-gate break; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate case INIT_ADV: 8530Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 8540Sstevel@tonic-gate delay = GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8550Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8560Sstevel@tonic-gate if (delay > ND_MAX_INITIAL_RTR_ADVERT_INTERVAL) 8570Sstevel@tonic-gate delay = ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 8580Sstevel@tonic-gate pi->pi_adv_time_left = delay; 8590Sstevel@tonic-gate } else { 8600Sstevel@tonic-gate pi->pi_adv_time_left = 8610Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8620Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8630Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate break; 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate case FINAL_ADV: 8680Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 8690Sstevel@tonic-gate pi->pi_adv_time_left = 8700Sstevel@tonic-gate ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 8710Sstevel@tonic-gate } else { 8720Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate break; 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate if (pi->pi_adv_state != NO_ADV) 8770Sstevel@tonic-gate return (pi->pi_adv_time_left); 8780Sstevel@tonic-gate else 8790Sstevel@tonic-gate return (TIMER_INFINITY); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * Router solicitation state machine. Used for everything but timer 8840Sstevel@tonic-gate * events which use solicit_event directly. 8850Sstevel@tonic-gate */ 8860Sstevel@tonic-gate void 8870Sstevel@tonic-gate check_to_solicit(struct phyint *pi, enum solicit_events event) 8880Sstevel@tonic-gate { 8890Sstevel@tonic-gate uint_t delay; 8900Sstevel@tonic-gate enum solicit_states old_state = pi->pi_sol_state; 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate if (debug & D_STATE) { 8930Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d\n", 8940Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 8950Sstevel@tonic-gate } 8960Sstevel@tonic-gate delay = solicit_event(pi, event, 0); 8970Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 8980Sstevel@tonic-gate /* Make sure the global next event is updated */ 8990Sstevel@tonic-gate timer_schedule(delay); 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate if (debug & D_STATE) { 9030Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d -> %d\n", 9040Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 9050Sstevel@tonic-gate (int)pi->pi_sol_state); 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate static void 9100Sstevel@tonic-gate daemonize_ndpd(void) 9110Sstevel@tonic-gate { 9120Sstevel@tonic-gate FILE *pidfp; 9130Sstevel@tonic-gate mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 9140Sstevel@tonic-gate struct itimerval it; 9150Sstevel@tonic-gate boolean_t timerval = _B_TRUE; 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate /* 9180Sstevel@tonic-gate * Need to get current timer settings so they can be restored 9190Sstevel@tonic-gate * after the fork(), as the it_value and it_interval values for 9200Sstevel@tonic-gate * the ITIMER_REAL timer are reset to 0 in the child process. 9210Sstevel@tonic-gate */ 9220Sstevel@tonic-gate if (getitimer(ITIMER_REAL, &it) < 0) { 9230Sstevel@tonic-gate if (debug & D_TIMER) 9240Sstevel@tonic-gate logmsg(LOG_DEBUG, 9250Sstevel@tonic-gate "daemonize_ndpd: failed to get itimerval\n"); 9260Sstevel@tonic-gate timerval = _B_FALSE; 9270Sstevel@tonic-gate } 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate /* Daemonize. */ 9300Sstevel@tonic-gate switch (fork()) { 9310Sstevel@tonic-gate case 0: 9320Sstevel@tonic-gate /* Child */ 9330Sstevel@tonic-gate break; 9340Sstevel@tonic-gate case -1: 9350Sstevel@tonic-gate logperror("fork"); 9360Sstevel@tonic-gate exit(1); 9370Sstevel@tonic-gate default: 9380Sstevel@tonic-gate /* Parent */ 9390Sstevel@tonic-gate _exit(0); 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate /* Store our process id, blow away any existing file if it exists. */ 9430Sstevel@tonic-gate if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 9440Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n", 9450Sstevel@tonic-gate argv0[0], strerror(errno)); 9460Sstevel@tonic-gate } else { 9470Sstevel@tonic-gate (void) fprintf(pidfp, "%ld\n", getpid()); 9480Sstevel@tonic-gate (void) fclose(pidfp); 9490Sstevel@tonic-gate (void) chmod(PATH_PID, pidmode); 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate (void) close(0); 9530Sstevel@tonic-gate (void) close(1); 9540Sstevel@tonic-gate (void) close(2); 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate (void) chdir("/"); 9570Sstevel@tonic-gate (void) open("/dev/null", O_RDWR); 9580Sstevel@tonic-gate (void) dup2(0, 1); 9590Sstevel@tonic-gate (void) dup2(0, 2); 9600Sstevel@tonic-gate (void) setsid(); 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate already_daemonized = _B_TRUE; 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate /* 9650Sstevel@tonic-gate * Restore timer values, if we were able to save them; if not, 9660Sstevel@tonic-gate * check and set the right value by calling run_timeouts(). 9670Sstevel@tonic-gate */ 9680Sstevel@tonic-gate if (timerval) { 9690Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 9700Sstevel@tonic-gate logperror("daemonize_ndpd: setitimer"); 9710Sstevel@tonic-gate exit(2); 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate } else { 9740Sstevel@tonic-gate run_timeouts(); 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate /* 9790Sstevel@tonic-gate * Check to see if the time is right to daemonize. The right time is when: 9800Sstevel@tonic-gate * 9810Sstevel@tonic-gate * 1. We haven't already daemonized. 9820Sstevel@tonic-gate * 2. We are not in debug mode. 9830Sstevel@tonic-gate * 3. All interfaces are marked IFF_NOXMIT. 9840Sstevel@tonic-gate * 4. All non-router interfaces have their prefixes set up and we're 9850Sstevel@tonic-gate * done sending router solicitations on those interfaces without 9860Sstevel@tonic-gate * prefixes. 9870Sstevel@tonic-gate */ 9880Sstevel@tonic-gate static void 9890Sstevel@tonic-gate check_daemonize(void) 9900Sstevel@tonic-gate { 9910Sstevel@tonic-gate struct phyint *pi; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate if (already_daemonized || debug != 0) 9940Sstevel@tonic-gate return; 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 9970Sstevel@tonic-gate if (!(pi->pi_flags & IFF_NOXMIT)) 9980Sstevel@tonic-gate break; 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate /* 10020Sstevel@tonic-gate * If we can't transmit on any of the interfaces there is no reason 10030Sstevel@tonic-gate * to hold up progress. 10040Sstevel@tonic-gate */ 10050Sstevel@tonic-gate if (pi == NULL) { 10060Sstevel@tonic-gate daemonize_ndpd(); 10070Sstevel@tonic-gate return; 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate /* Check all interfaces. If any are still soliciting, just return. */ 10110Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 10120Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements || 10130Sstevel@tonic-gate !(pi->pi_kernel_state & PI_PRESENT)) 10140Sstevel@tonic-gate continue; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 10170Sstevel@tonic-gate return; 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate daemonize_ndpd(); 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate /* 10240Sstevel@tonic-gate * Router solicitation state machine. 10250Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 10260Sstevel@tonic-gate * if never). 10270Sstevel@tonic-gate * For the SOL_TIMER event the caller passes in the number of milliseconds 10280Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 10290Sstevel@tonic-gate */ 10300Sstevel@tonic-gate uint_t 10310Sstevel@tonic-gate solicit_event(struct phyint *pi, enum solicit_events event, uint_t elapsed) 10320Sstevel@tonic-gate { 10330Sstevel@tonic-gate if (debug & D_STATE) { 10340Sstevel@tonic-gate logmsg(LOG_DEBUG, "solicit_event(%s, %d, %d) state %d\n", 10350Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_sol_state); 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 10390Sstevel@tonic-gate return (TIMER_INFINITY); 10400Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 10410Sstevel@tonic-gate if (debug & D_PKTOUT) { 10420Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RS packet on %s " 10430Sstevel@tonic-gate "(no route exchange on interface)\n", 10440Sstevel@tonic-gate pi->pi_name); 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate return (TIMER_INFINITY); 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate switch (event) { 10500Sstevel@tonic-gate case SOLICIT_OFF: 10510Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT; 10520Sstevel@tonic-gate check_daemonize(); 10530Sstevel@tonic-gate return (TIMER_INFINITY); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate case SOLICIT_DONE: 10560Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 10570Sstevel@tonic-gate check_daemonize(); 10580Sstevel@tonic-gate return (TIMER_INFINITY); 10590Sstevel@tonic-gate 10603431Scarlsonj case RESTART_INIT_SOLICIT: 10613431Scarlsonj /* 10623431Scarlsonj * This event allows us to start solicitation over again 10633431Scarlsonj * without losing the RA flags. We start solicitation over 10643431Scarlsonj * when we are missing an interface prefix for a newly- 10653431Scarlsonj * encountered DHCP interface. 10663431Scarlsonj */ 10673431Scarlsonj if (pi->pi_sol_state == INIT_SOLICIT) 10683431Scarlsonj return (pi->pi_sol_time_left); 10693431Scarlsonj pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS; 10703431Scarlsonj pi->pi_sol_time_left = 10713431Scarlsonj GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY); 10723431Scarlsonj pi->pi_sol_state = INIT_SOLICIT; 10733431Scarlsonj break; 10743431Scarlsonj 10750Sstevel@tonic-gate case START_INIT_SOLICIT: 10760Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 10770Sstevel@tonic-gate return (pi->pi_sol_time_left); 10783431Scarlsonj pi->pi_ra_flags = 0; 10790Sstevel@tonic-gate pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS; 10800Sstevel@tonic-gate pi->pi_sol_time_left = 10810Sstevel@tonic-gate GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY); 10820Sstevel@tonic-gate pi->pi_sol_state = INIT_SOLICIT; 10830Sstevel@tonic-gate break; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate case SOL_TIMER: 10860Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT) 10870Sstevel@tonic-gate return (TIMER_INFINITY); 10880Sstevel@tonic-gate /* Decrease time left */ 10890Sstevel@tonic-gate if (pi->pi_sol_time_left >= elapsed) 10900Sstevel@tonic-gate pi->pi_sol_time_left -= elapsed; 10910Sstevel@tonic-gate else 10920Sstevel@tonic-gate pi->pi_sol_time_left = 0; 10930Sstevel@tonic-gate break; 10940Sstevel@tonic-gate default: 10950Sstevel@tonic-gate logmsg(LOG_ERR, "solicit_event: Unknown event %d\n", 10960Sstevel@tonic-gate (int)event); 10970Sstevel@tonic-gate return (TIMER_INFINITY); 10980Sstevel@tonic-gate } 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate if (pi->pi_sol_time_left != 0) 11010Sstevel@tonic-gate return (pi->pi_sol_time_left); 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate /* Send solicitation and calculate next time */ 11040Sstevel@tonic-gate switch (pi->pi_sol_state) { 11050Sstevel@tonic-gate case INIT_SOLICIT: 11060Sstevel@tonic-gate solicit(&v6allrouters, pi); 11070Sstevel@tonic-gate if (--pi->pi_sol_count == 0) { 11084106Scarlsonj if (debug & D_STATE) { 11094106Scarlsonj logmsg(LOG_DEBUG, "solicit_event: no routers " 11104106Scarlsonj "found on %s; assuming default flags\n", 11114106Scarlsonj pi->pi_name); 11124106Scarlsonj } 1113*12016SGirish.Moodalbail@Sun.COM if (pi->pi_autoconf && pi->pi_StatefulAddrConf) { 11143431Scarlsonj pi->pi_ra_flags |= ND_RA_FLAG_MANAGED | 11153431Scarlsonj ND_RA_FLAG_OTHER; 11163431Scarlsonj start_dhcp(pi); 11173431Scarlsonj } 11180Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 11190Sstevel@tonic-gate check_daemonize(); 11200Sstevel@tonic-gate return (TIMER_INFINITY); 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate pi->pi_sol_time_left = ND_RTR_SOLICITATION_INTERVAL; 11230Sstevel@tonic-gate return (pi->pi_sol_time_left); 11240Sstevel@tonic-gate case NO_SOLICIT: 11250Sstevel@tonic-gate case DONE_SOLICIT: 11260Sstevel@tonic-gate return (TIMER_INFINITY); 11270Sstevel@tonic-gate default: 11280Sstevel@tonic-gate return (pi->pi_sol_time_left); 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate /* 11330Sstevel@tonic-gate * Timer mechanism using relative time (in milliseconds) from the 11340Sstevel@tonic-gate * previous timer event. Timers exceeding TIMER_INFINITY milliseconds 11350Sstevel@tonic-gate * will fire after TIMER_INFINITY milliseconds. 11360Sstevel@tonic-gate */ 11370Sstevel@tonic-gate static uint_t timer_previous; /* When last SIGALRM occurred */ 11380Sstevel@tonic-gate static uint_t timer_next; /* Currently scheduled timeout */ 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate static void 11410Sstevel@tonic-gate timer_init(void) 11420Sstevel@tonic-gate { 11430Sstevel@tonic-gate timer_previous = getcurrenttime(); 11440Sstevel@tonic-gate timer_next = TIMER_INFINITY; 11450Sstevel@tonic-gate run_timeouts(); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate /* 11490Sstevel@tonic-gate * Make sure the next SIGALRM occurs delay milliseconds from the current 11500Sstevel@tonic-gate * time if not earlier. 11510Sstevel@tonic-gate * Handles getcurrenttime (32 bit integer holding milliseconds) wraparound 11520Sstevel@tonic-gate * by treating differences greater than 0x80000000 as negative. 11530Sstevel@tonic-gate */ 11540Sstevel@tonic-gate void 11550Sstevel@tonic-gate timer_schedule(uint_t delay) 11560Sstevel@tonic-gate { 11570Sstevel@tonic-gate uint_t now; 11580Sstevel@tonic-gate struct itimerval itimerval; 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate now = getcurrenttime(); 11610Sstevel@tonic-gate if (debug & D_TIMER) { 11620Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): now %u next %u\n", 11630Sstevel@tonic-gate delay, now, timer_next); 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate /* Will this timer occur before the currently scheduled SIGALRM? */ 11660Sstevel@tonic-gate if (delay >= timer_next - now) { 11670Sstevel@tonic-gate if (debug & D_TIMER) { 11680Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): no action - " 11690Sstevel@tonic-gate "next in %u ms\n", 11700Sstevel@tonic-gate delay, timer_next - now); 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate return; 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate if (delay == 0) { 11750Sstevel@tonic-gate /* Minimum allowed delay */ 11760Sstevel@tonic-gate delay = 1; 11770Sstevel@tonic-gate } 11780Sstevel@tonic-gate timer_next = now + delay; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate itimerval.it_value.tv_sec = delay / 1000; 11810Sstevel@tonic-gate itimerval.it_value.tv_usec = (delay % 1000) * 1000; 11820Sstevel@tonic-gate itimerval.it_interval.tv_sec = 0; 11830Sstevel@tonic-gate itimerval.it_interval.tv_usec = 0; 11840Sstevel@tonic-gate if (debug & D_TIMER) { 11850Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): sec %lu usec %lu\n", 11860Sstevel@tonic-gate delay, 11870Sstevel@tonic-gate itimerval.it_value.tv_sec, itimerval.it_value.tv_usec); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) { 11900Sstevel@tonic-gate logperror("timer_schedule: setitimer"); 11910Sstevel@tonic-gate exit(2); 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate /* 11960Sstevel@tonic-gate * Conditional running of timer. If more than 'minimal_time' millseconds 11970Sstevel@tonic-gate * since the timer routines were last run we run them. 11980Sstevel@tonic-gate * Used when packets arrive. 11990Sstevel@tonic-gate */ 12000Sstevel@tonic-gate static void 12010Sstevel@tonic-gate conditional_run_timeouts(uint_t minimal_time) 12020Sstevel@tonic-gate { 12030Sstevel@tonic-gate uint_t now; 12040Sstevel@tonic-gate uint_t elapsed; 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate now = getcurrenttime(); 12070Sstevel@tonic-gate elapsed = now - timer_previous; 12080Sstevel@tonic-gate if (elapsed > minimal_time) { 12090Sstevel@tonic-gate if (debug & D_TIMER) { 12100Sstevel@tonic-gate logmsg(LOG_DEBUG, "conditional_run_timeouts: " 12110Sstevel@tonic-gate "elapsed %d\n", elapsed); 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate run_timeouts(); 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate } 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate /* 12180Sstevel@tonic-gate * Timer has fired. 12190Sstevel@tonic-gate * Determine when the next timer event will occur by asking all 12200Sstevel@tonic-gate * the timer routines. 12210Sstevel@tonic-gate * Should not be called from a timer routine but in some cases this is 12220Sstevel@tonic-gate * done because the code doesn't know that e.g. it was called from 12230Sstevel@tonic-gate * ifconfig_timer(). In this case the nested run_timeouts will just return but 12240Sstevel@tonic-gate * the running run_timeouts will ensure to call all the timer functions by 12250Sstevel@tonic-gate * looping once more. 12260Sstevel@tonic-gate */ 12270Sstevel@tonic-gate static void 12280Sstevel@tonic-gate run_timeouts(void) 12290Sstevel@tonic-gate { 12300Sstevel@tonic-gate uint_t now; 12310Sstevel@tonic-gate uint_t elapsed; 12320Sstevel@tonic-gate uint_t next; 12330Sstevel@tonic-gate uint_t nexti; 12340Sstevel@tonic-gate struct phyint *pi; 12350Sstevel@tonic-gate struct phyint *next_pi; 12360Sstevel@tonic-gate struct prefix *pr; 12370Sstevel@tonic-gate struct prefix *next_pr; 12380Sstevel@tonic-gate struct adv_prefix *adv_pr; 12390Sstevel@tonic-gate struct adv_prefix *next_adv_pr; 12400Sstevel@tonic-gate struct router *dr; 12410Sstevel@tonic-gate struct router *next_dr; 12420Sstevel@tonic-gate static boolean_t timeout_running; 12430Sstevel@tonic-gate static boolean_t do_retry; 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate if (timeout_running) { 12460Sstevel@tonic-gate if (debug & D_TIMER) 12470Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: nested call\n"); 12480Sstevel@tonic-gate do_retry = _B_TRUE; 12490Sstevel@tonic-gate return; 12500Sstevel@tonic-gate } 12510Sstevel@tonic-gate timeout_running = _B_TRUE; 12520Sstevel@tonic-gate retry: 12530Sstevel@tonic-gate /* How much time since the last time we were called? */ 12540Sstevel@tonic-gate now = getcurrenttime(); 12550Sstevel@tonic-gate elapsed = now - timer_previous; 12560Sstevel@tonic-gate timer_previous = now; 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate if (debug & D_TIMER) 12590Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: elapsed %d\n", elapsed); 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate next = TIMER_INFINITY; 12620Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 12630Sstevel@tonic-gate next_pi = pi->pi_next; 12640Sstevel@tonic-gate nexti = phyint_timer(pi, elapsed); 12650Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12660Sstevel@tonic-gate next = nexti; 12670Sstevel@tonic-gate if (debug & D_TIMER) { 12680Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pi %s): %d -> %u ms\n", 12690Sstevel@tonic-gate pi->pi_name, nexti, next); 12700Sstevel@tonic-gate } 12710Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 12720Sstevel@tonic-gate next_pr = pr->pr_next; 12730Sstevel@tonic-gate nexti = prefix_timer(pr, elapsed); 12740Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12750Sstevel@tonic-gate next = nexti; 12760Sstevel@tonic-gate if (debug & D_TIMER) { 12770Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pr %s): " 12780Sstevel@tonic-gate "%d -> %u ms\n", pr->pr_name, nexti, next); 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate } 12810Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 12820Sstevel@tonic-gate adv_pr = next_adv_pr) { 12830Sstevel@tonic-gate next_adv_pr = adv_pr->adv_pr_next; 12840Sstevel@tonic-gate nexti = adv_prefix_timer(adv_pr, elapsed); 12850Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12860Sstevel@tonic-gate next = nexti; 12870Sstevel@tonic-gate if (debug & D_TIMER) { 12880Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts " 12890Sstevel@tonic-gate "(adv pr on %s): %d -> %u ms\n", 12900Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 12910Sstevel@tonic-gate nexti, next); 12920Sstevel@tonic-gate } 12930Sstevel@tonic-gate } 12940Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) { 12950Sstevel@tonic-gate next_dr = dr->dr_next; 12960Sstevel@tonic-gate nexti = router_timer(dr, elapsed); 12970Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12980Sstevel@tonic-gate next = nexti; 12990Sstevel@tonic-gate if (debug & D_TIMER) { 13000Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (dr): " 13010Sstevel@tonic-gate "%d -> %u ms\n", nexti, next); 13020Sstevel@tonic-gate } 13030Sstevel@tonic-gate } 13040Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled) { 13050Sstevel@tonic-gate nexti = tmptoken_timer(pi, elapsed); 13060Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 13070Sstevel@tonic-gate next = nexti; 13080Sstevel@tonic-gate if (debug & D_TIMER) { 13090Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (tmp on %s): " 13100Sstevel@tonic-gate "%d -> %u ms\n", pi->pi_name, nexti, next); 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate /* 13150Sstevel@tonic-gate * Make sure the timer functions are run at least once 13160Sstevel@tonic-gate * an hour. 13170Sstevel@tonic-gate */ 13180Sstevel@tonic-gate if (next == TIMER_INFINITY) 13190Sstevel@tonic-gate next = 3600 * 1000; /* 1 hour */ 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate if (debug & D_TIMER) 13220Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: %u ms\n", next); 13230Sstevel@tonic-gate timer_schedule(next); 13240Sstevel@tonic-gate if (do_retry) { 13250Sstevel@tonic-gate if (debug & D_TIMER) 13260Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: retry\n"); 13270Sstevel@tonic-gate do_retry = _B_FALSE; 13280Sstevel@tonic-gate goto retry; 13290Sstevel@tonic-gate } 13300Sstevel@tonic-gate timeout_running = _B_FALSE; 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate static int eventpipe_read = -1; /* Used for synchronous signal delivery */ 13340Sstevel@tonic-gate static int eventpipe_write = -1; 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate /* 13370Sstevel@tonic-gate * Ensure that signals are processed synchronously with the rest of 13380Sstevel@tonic-gate * the code by just writing a one character signal number on the pipe. 13390Sstevel@tonic-gate * The poll loop will pick this up and process the signal event. 13400Sstevel@tonic-gate */ 13410Sstevel@tonic-gate static void 13420Sstevel@tonic-gate sig_handler(int signo) 13430Sstevel@tonic-gate { 13440Sstevel@tonic-gate uchar_t buf = (uchar_t)signo; 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate if (eventpipe_write == -1) { 13470Sstevel@tonic-gate logmsg(LOG_ERR, "sig_handler: no pipe\n"); 13480Sstevel@tonic-gate return; 13490Sstevel@tonic-gate } 13500Sstevel@tonic-gate if (write(eventpipe_write, &buf, sizeof (buf)) < 0) 13510Sstevel@tonic-gate logperror("sig_handler: write"); 13520Sstevel@tonic-gate } 13530Sstevel@tonic-gate 13540Sstevel@tonic-gate /* 13550Sstevel@tonic-gate * Pick up a signal "byte" from the pipe and process it. 13560Sstevel@tonic-gate */ 13570Sstevel@tonic-gate static void 13580Sstevel@tonic-gate in_signal(int fd) 13590Sstevel@tonic-gate { 13600Sstevel@tonic-gate uchar_t buf; 13610Sstevel@tonic-gate struct phyint *pi; 13620Sstevel@tonic-gate struct phyint *next_pi; 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate switch (read(fd, &buf, sizeof (buf))) { 13650Sstevel@tonic-gate case -1: 13660Sstevel@tonic-gate logperror("in_signal: read"); 13670Sstevel@tonic-gate exit(1); 13680Sstevel@tonic-gate /* NOTREACHED */ 13690Sstevel@tonic-gate case 1: 13700Sstevel@tonic-gate break; 13710Sstevel@tonic-gate case 0: 13720Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read eof\n"); 13730Sstevel@tonic-gate exit(1); 13740Sstevel@tonic-gate /* NOTREACHED */ 13750Sstevel@tonic-gate default: 13760Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read > 1\n"); 13770Sstevel@tonic-gate exit(1); 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate if (debug & D_TIMER) 13810Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal() got %d\n", buf); 13820Sstevel@tonic-gate 13830Sstevel@tonic-gate switch (buf) { 13840Sstevel@tonic-gate case SIGALRM: 13850Sstevel@tonic-gate if (debug & D_TIMER) { 13860Sstevel@tonic-gate uint_t now = getcurrenttime(); 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal(SIGALRM) delta %u\n", 13890Sstevel@tonic-gate now - timer_next); 13900Sstevel@tonic-gate } 13910Sstevel@tonic-gate timer_next = TIMER_INFINITY; 13920Sstevel@tonic-gate run_timeouts(); 13930Sstevel@tonic-gate break; 13940Sstevel@tonic-gate case SIGHUP: 13950Sstevel@tonic-gate /* Re-read config file by exec'ing ourselves */ 13960Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 13970Sstevel@tonic-gate next_pi = pi->pi_next; 13980Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 13990Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 14000Sstevel@tonic-gate 1401*12016SGirish.Moodalbail@Sun.COM /* 1402*12016SGirish.Moodalbail@Sun.COM * Remove all the configured addresses. 1403*12016SGirish.Moodalbail@Sun.COM * Remove the addrobj names created with ipmgmtd. 1404*12016SGirish.Moodalbail@Sun.COM * Release the dhcpv6 addresses if any. 1405*12016SGirish.Moodalbail@Sun.COM * Cleanup the phyints. 1406*12016SGirish.Moodalbail@Sun.COM */ 14070Sstevel@tonic-gate phyint_delete(pi); 14080Sstevel@tonic-gate } 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate /* 14110Sstevel@tonic-gate * Prevent fd leaks. Everything gets re-opened at start-up 14120Sstevel@tonic-gate * time. 0, 1, and 2 are closed and re-opened as 14130Sstevel@tonic-gate * /dev/null, so we'll leave those open. 14140Sstevel@tonic-gate */ 14150Sstevel@tonic-gate closefrom(3); 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate logmsg(LOG_ERR, "SIGHUP: restart and reread config file\n"); 14180Sstevel@tonic-gate (void) execv(argv0[0], argv0); 14190Sstevel@tonic-gate (void) unlink(PATH_PID); 14200Sstevel@tonic-gate _exit(0177); 14210Sstevel@tonic-gate /* NOTREACHED */ 14220Sstevel@tonic-gate case SIGUSR1: 14230Sstevel@tonic-gate logmsg(LOG_DEBUG, "Printing configuration:\n"); 14240Sstevel@tonic-gate phyint_print_all(); 14250Sstevel@tonic-gate break; 14260Sstevel@tonic-gate case SIGINT: 14270Sstevel@tonic-gate case SIGTERM: 14280Sstevel@tonic-gate case SIGQUIT: 14290Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 14300Sstevel@tonic-gate next_pi = pi->pi_next; 14310Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 14320Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate phyint_delete(pi); 14350Sstevel@tonic-gate } 14363284Sapersson (void) unlink(NDPD_SNMP_SOCKET); 14370Sstevel@tonic-gate (void) unlink(PATH_PID); 14380Sstevel@tonic-gate exit(0); 14390Sstevel@tonic-gate /* NOTREACHED */ 14400Sstevel@tonic-gate case 255: 14410Sstevel@tonic-gate /* 1442*12016SGirish.Moodalbail@Sun.COM * Special "signal" from loopback_ra_enqueue. 14430Sstevel@tonic-gate * Handle any queued loopback router advertisements. 14440Sstevel@tonic-gate */ 14450Sstevel@tonic-gate loopback_ra_dequeue(); 14460Sstevel@tonic-gate break; 14470Sstevel@tonic-gate default: 14480Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: unknown signal: %d\n", buf); 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate } 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate /* 14530Sstevel@tonic-gate * Create pipe for signal delivery and set up signal handlers. 14540Sstevel@tonic-gate */ 14550Sstevel@tonic-gate static void 14560Sstevel@tonic-gate setup_eventpipe(void) 14570Sstevel@tonic-gate { 14580Sstevel@tonic-gate int fds[2]; 14590Sstevel@tonic-gate struct sigaction act; 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate if ((pipe(fds)) < 0) { 14620Sstevel@tonic-gate logperror("setup_eventpipe: pipe"); 14630Sstevel@tonic-gate exit(1); 14640Sstevel@tonic-gate } 14650Sstevel@tonic-gate eventpipe_read = fds[0]; 14660Sstevel@tonic-gate eventpipe_write = fds[1]; 14670Sstevel@tonic-gate if (poll_add(eventpipe_read) == -1) { 14680Sstevel@tonic-gate exit(1); 14690Sstevel@tonic-gate } 14700Sstevel@tonic-gate act.sa_handler = sig_handler; 14710Sstevel@tonic-gate act.sa_flags = SA_RESTART; 14720Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate (void) sigset(SIGHUP, sig_handler); 14750Sstevel@tonic-gate (void) sigset(SIGUSR1, sig_handler); 14760Sstevel@tonic-gate (void) sigset(SIGTERM, sig_handler); 14770Sstevel@tonic-gate (void) sigset(SIGINT, sig_handler); 14780Sstevel@tonic-gate (void) sigset(SIGQUIT, sig_handler); 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate /* 14820Sstevel@tonic-gate * Create a routing socket for receiving RTM_IFINFO messages and initialize 14830Sstevel@tonic-gate * the routing socket message header and as much of the sockaddrs as possible. 14840Sstevel@tonic-gate */ 14850Sstevel@tonic-gate static int 14860Sstevel@tonic-gate setup_rtsock(void) 14870Sstevel@tonic-gate { 14880Sstevel@tonic-gate int s; 14890Sstevel@tonic-gate int ret; 14900Sstevel@tonic-gate char *cp; 14910Sstevel@tonic-gate struct sockaddr_in6 *sin6; 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, AF_INET6); 14940Sstevel@tonic-gate if (s == -1) { 14950Sstevel@tonic-gate logperror("socket(PF_ROUTE)"); 14960Sstevel@tonic-gate exit(1); 14970Sstevel@tonic-gate } 14980Sstevel@tonic-gate ret = fcntl(s, F_SETFL, O_NDELAY|O_NONBLOCK); 14990Sstevel@tonic-gate if (ret < 0) { 15000Sstevel@tonic-gate logperror("fcntl(O_NDELAY)"); 15010Sstevel@tonic-gate exit(1); 15020Sstevel@tonic-gate } 15030Sstevel@tonic-gate if (poll_add(s) == -1) { 15040Sstevel@tonic-gate exit(1); 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate /* 15080Sstevel@tonic-gate * Allocate storage for the routing socket message. 15090Sstevel@tonic-gate */ 15100Sstevel@tonic-gate rt_msg = (struct rt_msghdr *)malloc(NDP_RTM_MSGLEN); 15110Sstevel@tonic-gate if (rt_msg == NULL) { 15120Sstevel@tonic-gate logperror("malloc"); 15130Sstevel@tonic-gate exit(1); 15140Sstevel@tonic-gate } 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate /* 15170Sstevel@tonic-gate * Initialize the routing socket message by zero-filling it and then 15180Sstevel@tonic-gate * setting the fields where are constant through the lifetime of the 15190Sstevel@tonic-gate * process. 15200Sstevel@tonic-gate */ 15210Sstevel@tonic-gate bzero(rt_msg, NDP_RTM_MSGLEN); 15220Sstevel@tonic-gate rt_msg->rtm_msglen = NDP_RTM_MSGLEN; 15230Sstevel@tonic-gate rt_msg->rtm_version = RTM_VERSION; 15240Sstevel@tonic-gate rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP; 15250Sstevel@tonic-gate rt_msg->rtm_pid = getpid(); 15260Sstevel@tonic-gate if (rt_msg->rtm_pid < 0) { 15270Sstevel@tonic-gate logperror("getpid"); 15280Sstevel@tonic-gate exit(1); 15290Sstevel@tonic-gate } 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate /* 15320Sstevel@tonic-gate * The RTA_DST sockaddr does not change during the lifetime of the 15330Sstevel@tonic-gate * process so it can be completely initialized at this time. 15340Sstevel@tonic-gate */ 15350Sstevel@tonic-gate cp = (char *)rt_msg + sizeof (struct rt_msghdr); 15360Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 15370Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15380Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 15390Sstevel@tonic-gate 15400Sstevel@tonic-gate /* 15410Sstevel@tonic-gate * Initialize the constant portion of the RTA_GATEWAY sockaddr. 15420Sstevel@tonic-gate */ 15430Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15440Sstevel@tonic-gate rta_gateway = (struct sockaddr_in6 *)cp; 15450Sstevel@tonic-gate rta_gateway->sin6_family = AF_INET6; 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate /* 15480Sstevel@tonic-gate * The RTA_NETMASK sockaddr does not change during the lifetime of the 15490Sstevel@tonic-gate * process so it can be completely initialized at this time. 15500Sstevel@tonic-gate */ 15510Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15520Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 15530Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15540Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 15550Sstevel@tonic-gate 15560Sstevel@tonic-gate /* 15570Sstevel@tonic-gate * Initialize the constant portion of the RTA_IFP sockaddr. 15580Sstevel@tonic-gate */ 15590Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15600Sstevel@tonic-gate rta_ifp = (struct sockaddr_dl *)cp; 15610Sstevel@tonic-gate rta_ifp->sdl_family = AF_LINK; 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate return (s); 15640Sstevel@tonic-gate } 15650Sstevel@tonic-gate 15663284Sapersson static int 15673284Sapersson setup_mibsock(void) 15683284Sapersson { 15693284Sapersson int sock; 15703284Sapersson int ret; 15713284Sapersson int len; 15723284Sapersson struct sockaddr_un laddr; 15733284Sapersson 15743284Sapersson sock = socket(AF_UNIX, SOCK_DGRAM, 0); 15753284Sapersson if (sock == -1) { 15763284Sapersson logperror("setup_mibsock: socket(AF_UNIX)"); 15773284Sapersson exit(1); 15783284Sapersson } 15793284Sapersson 15803284Sapersson bzero(&laddr, sizeof (laddr)); 15813284Sapersson laddr.sun_family = AF_UNIX; 15823284Sapersson 15833284Sapersson (void) strncpy(laddr.sun_path, NDPD_SNMP_SOCKET, 15843284Sapersson sizeof (laddr.sun_path)); 15853284Sapersson len = sizeof (struct sockaddr_un); 15863284Sapersson 15873284Sapersson (void) unlink(NDPD_SNMP_SOCKET); 15883284Sapersson ret = bind(sock, (struct sockaddr *)&laddr, len); 15893284Sapersson if (ret < 0) { 15903284Sapersson logperror("setup_mibsock: bind\n"); 15913284Sapersson exit(1); 15923284Sapersson } 15933284Sapersson 15943284Sapersson ret = fcntl(sock, F_SETFL, O_NONBLOCK); 15953284Sapersson if (ret < 0) { 15963284Sapersson logperror("fcntl(O_NONBLOCK)"); 15973284Sapersson exit(1); 15983284Sapersson } 15993284Sapersson if (poll_add(sock) == -1) { 16003284Sapersson exit(1); 16013284Sapersson } 16023284Sapersson return (sock); 16033284Sapersson } 16043284Sapersson 16050Sstevel@tonic-gate /* 16060Sstevel@tonic-gate * Retrieve one routing socket message. If RTM_IFINFO indicates 16070Sstevel@tonic-gate * new phyint do a full scan of the interfaces. If RTM_IFINFO 16082546Scarlsonj * indicates an existing phyint, only scan that phyint and associated 16090Sstevel@tonic-gate * prefixes. 16100Sstevel@tonic-gate */ 16110Sstevel@tonic-gate static void 16120Sstevel@tonic-gate process_rtsock(int rtsock) 16130Sstevel@tonic-gate { 16140Sstevel@tonic-gate int n; 16150Sstevel@tonic-gate #define MSG_SIZE 2048/8 16160Sstevel@tonic-gate int64_t msg[MSG_SIZE]; 16170Sstevel@tonic-gate struct rt_msghdr *rtm; 16180Sstevel@tonic-gate struct if_msghdr *ifm; 16190Sstevel@tonic-gate struct phyint *pi; 16200Sstevel@tonic-gate struct prefix *pr; 16210Sstevel@tonic-gate boolean_t need_initifs = _B_FALSE; 16220Sstevel@tonic-gate boolean_t need_ifscan = _B_FALSE; 16230Sstevel@tonic-gate int64_t ifscan_msg[10][MSG_SIZE]; 16240Sstevel@tonic-gate int ifscan_index = 0; 16250Sstevel@tonic-gate int i; 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate /* Empty the rtsock and coealesce all the work that we have */ 16280Sstevel@tonic-gate while (ifscan_index < 10) { 16290Sstevel@tonic-gate n = read(rtsock, msg, sizeof (msg)); 16300Sstevel@tonic-gate if (n <= 0) { 16310Sstevel@tonic-gate /* No more messages */ 16320Sstevel@tonic-gate break; 16330Sstevel@tonic-gate } 16340Sstevel@tonic-gate rtm = (struct rt_msghdr *)msg; 16350Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 16360Sstevel@tonic-gate logmsg(LOG_ERR, 16370Sstevel@tonic-gate "process_rtsock: version %d not understood\n", 16380Sstevel@tonic-gate rtm->rtm_version); 16390Sstevel@tonic-gate return; 16400Sstevel@tonic-gate } 16410Sstevel@tonic-gate switch (rtm->rtm_type) { 16420Sstevel@tonic-gate case RTM_NEWADDR: 16430Sstevel@tonic-gate case RTM_DELADDR: 16440Sstevel@tonic-gate /* 16450Sstevel@tonic-gate * Some logical interface has changed - have to scan 16460Sstevel@tonic-gate * everything to determine what actually changed. 16470Sstevel@tonic-gate */ 16480Sstevel@tonic-gate if (debug & D_IFSCAN) { 16490Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: " 16500Sstevel@tonic-gate "message %d\n", rtm->rtm_type); 16510Sstevel@tonic-gate } 16520Sstevel@tonic-gate need_initifs = _B_TRUE; 16530Sstevel@tonic-gate break; 16540Sstevel@tonic-gate case RTM_IFINFO: 16550Sstevel@tonic-gate need_ifscan = _B_TRUE; 16560Sstevel@tonic-gate (void) memcpy(ifscan_msg[ifscan_index], rtm, 16570Sstevel@tonic-gate sizeof (msg)); 16580Sstevel@tonic-gate ifscan_index++; 16590Sstevel@tonic-gate /* Handled below */ 16600Sstevel@tonic-gate break; 16610Sstevel@tonic-gate default: 16620Sstevel@tonic-gate /* Not interesting */ 16630Sstevel@tonic-gate break; 16640Sstevel@tonic-gate } 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate /* 16670Sstevel@tonic-gate * If we do full scan i.e initifs, we don't need to 16680Sstevel@tonic-gate * scan a particular interface as we should have 16690Sstevel@tonic-gate * done that as part of initifs. 16700Sstevel@tonic-gate */ 16710Sstevel@tonic-gate if (need_initifs) { 16720Sstevel@tonic-gate initifs(_B_FALSE); 16730Sstevel@tonic-gate return; 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate if (!need_ifscan) 16770Sstevel@tonic-gate return; 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate for (i = 0; i < ifscan_index; i++) { 16800Sstevel@tonic-gate ifm = (struct if_msghdr *)ifscan_msg[i]; 16810Sstevel@tonic-gate if (debug & D_IFSCAN) 16820Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: index %d\n", 16830Sstevel@tonic-gate ifm->ifm_index); 16840Sstevel@tonic-gate 16850Sstevel@tonic-gate pi = phyint_lookup_on_index(ifm->ifm_index); 16860Sstevel@tonic-gate if (pi == NULL) { 16870Sstevel@tonic-gate /* 16880Sstevel@tonic-gate * A new physical interface. Do a full scan of the 16890Sstevel@tonic-gate * to catch any new logical interfaces. 16900Sstevel@tonic-gate */ 16910Sstevel@tonic-gate initifs(_B_FALSE); 16920Sstevel@tonic-gate return; 16930Sstevel@tonic-gate } 16940Sstevel@tonic-gate 16958485SPeter.Memishian@Sun.COM if (ifm->ifm_flags != (uint_t)pi->pi_flags) { 16960Sstevel@tonic-gate if (debug & D_IFSCAN) { 16970Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: clr for " 16988485SPeter.Memishian@Sun.COM "%s old flags 0x%llx new flags 0x%x\n", 16990Sstevel@tonic-gate pi->pi_name, pi->pi_flags, ifm->ifm_flags); 17000Sstevel@tonic-gate } 17010Sstevel@tonic-gate } 17020Sstevel@tonic-gate 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate /* 17050Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 17060Sstevel@tonic-gate * which have disappeared from the kernel. 17070Sstevel@tonic-gate * if_process will set pr_in_use when it finds the 17080Sstevel@tonic-gate * interface in the kernel. 17090Sstevel@tonic-gate * Before re-examining the state of the interfaces, 17100Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 17110Sstevel@tonic-gate */ 17120Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 17130Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 17140Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 17150Sstevel@tonic-gate } 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate if (ifsock < 0) { 17180Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 17190Sstevel@tonic-gate if (ifsock < 0) { 17200Sstevel@tonic-gate logperror("process_rtsock: socket"); 17210Sstevel@tonic-gate return; 17220Sstevel@tonic-gate } 17230Sstevel@tonic-gate } 17240Sstevel@tonic-gate if_process(ifsock, pi->pi_name, _B_FALSE); 17250Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 17260Sstevel@tonic-gate if_process(ifsock, pr->pr_name, _B_FALSE); 17270Sstevel@tonic-gate } 17280Sstevel@tonic-gate /* 17290Sstevel@tonic-gate * If interface (still) exists in kernel, set 17300Sstevel@tonic-gate * pi_state to indicate that. 17310Sstevel@tonic-gate */ 17320Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 17330Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 17340Sstevel@tonic-gate } 17350Sstevel@tonic-gate check_if_removed(pi); 17360Sstevel@tonic-gate if (show_ifs) 17370Sstevel@tonic-gate phyint_print_all(); 17380Sstevel@tonic-gate } 17390Sstevel@tonic-gate } 17400Sstevel@tonic-gate 17413284Sapersson static void 17423284Sapersson process_mibsock(int mibsock) 17433284Sapersson { 17443284Sapersson struct phyint *pi; 17453284Sapersson socklen_t fromlen; 17463284Sapersson struct sockaddr_un from; 17473284Sapersson ndpd_info_t ndpd_info; 17483284Sapersson ssize_t len; 17493284Sapersson int command; 17503284Sapersson 17513284Sapersson fromlen = (socklen_t)sizeof (from); 17523284Sapersson len = recvfrom(mibsock, &command, sizeof (int), 0, 17533284Sapersson (struct sockaddr *)&from, &fromlen); 17543284Sapersson 17553284Sapersson if (len < sizeof (int) || command != NDPD_SNMP_INFO_REQ) { 17563284Sapersson logperror("process_mibsock: bad command \n"); 17573284Sapersson return; 17583284Sapersson } 17593284Sapersson 17603284Sapersson ndpd_info.info_type = NDPD_SNMP_INFO_RESPONSE; 17613284Sapersson ndpd_info.info_version = NDPD_SNMP_INFO_VER; 17623284Sapersson ndpd_info.info_num_of_phyints = num_of_phyints; 17633284Sapersson 17643284Sapersson (void) sendto(mibsock, &ndpd_info, sizeof (ndpd_info_t), 0, 17653284Sapersson (struct sockaddr *)&from, fromlen); 17663284Sapersson 17673284Sapersson for (pi = phyints; pi != NULL; pi = pi->pi_next) { 17683284Sapersson int prefixes; 17693284Sapersson int routers; 17703284Sapersson struct prefix *prefix_list; 17713284Sapersson struct router *router_list; 17723284Sapersson ndpd_phyint_info_t phyint; 17733284Sapersson ndpd_prefix_info_t prefix; 17743284Sapersson ndpd_router_info_t router; 17753284Sapersson /* 17763284Sapersson * get number of prefixes 17773284Sapersson */ 17783284Sapersson routers = 0; 17793284Sapersson prefixes = 0; 17803284Sapersson prefix_list = pi->pi_prefix_list; 17813284Sapersson while (prefix_list != NULL) { 17823284Sapersson prefixes++; 17833284Sapersson prefix_list = prefix_list->pr_next; 17843284Sapersson } 17853284Sapersson 17863284Sapersson /* 17873284Sapersson * get number of routers 17883284Sapersson */ 17893284Sapersson router_list = pi->pi_router_list; 17903284Sapersson while (router_list != NULL) { 17913284Sapersson routers++; 17923284Sapersson router_list = router_list->dr_next; 17933284Sapersson } 17943284Sapersson 17953284Sapersson phyint.phyint_info_type = NDPD_PHYINT_INFO; 17963284Sapersson phyint.phyint_info_version = NDPD_PHYINT_INFO_VER; 17973284Sapersson phyint.phyint_index = pi->pi_index; 17983284Sapersson bcopy(pi->pi_config, 17993284Sapersson phyint.phyint_config, I_IFSIZE); 18003284Sapersson phyint.phyint_num_of_prefixes = prefixes; 18013284Sapersson phyint.phyint_num_of_routers = routers; 18023284Sapersson (void) sendto(mibsock, &phyint, sizeof (phyint), 0, 18033284Sapersson (struct sockaddr *)&from, fromlen); 18043284Sapersson 18053284Sapersson /* 18063284Sapersson * Copy prefix information 18073284Sapersson */ 18083284Sapersson 18093284Sapersson prefix_list = pi->pi_prefix_list; 18103284Sapersson while (prefix_list != NULL) { 18113284Sapersson prefix.prefix_info_type = NDPD_PREFIX_INFO; 18123284Sapersson prefix.prefix_info_version = NDPD_PREFIX_INFO_VER; 18133284Sapersson prefix.prefix_prefix = prefix_list->pr_prefix; 18143284Sapersson prefix.prefix_len = prefix_list->pr_prefix_len; 18153284Sapersson prefix.prefix_flags = prefix_list->pr_flags; 18163284Sapersson prefix.prefix_phyint_index = pi->pi_index; 18173284Sapersson prefix.prefix_ValidLifetime = 18183284Sapersson prefix_list->pr_ValidLifetime; 18193284Sapersson prefix.prefix_PreferredLifetime = 18203284Sapersson prefix_list->pr_PreferredLifetime; 18213284Sapersson prefix.prefix_OnLinkLifetime = 18223284Sapersson prefix_list->pr_OnLinkLifetime; 18233284Sapersson prefix.prefix_OnLinkFlag = 18243284Sapersson prefix_list->pr_OnLinkFlag; 18253284Sapersson prefix.prefix_AutonomousFlag = 18263284Sapersson prefix_list->pr_AutonomousFlag; 18273284Sapersson (void) sendto(mibsock, &prefix, sizeof (prefix), 0, 18283284Sapersson (struct sockaddr *)&from, fromlen); 18293284Sapersson prefix_list = prefix_list->pr_next; 18303284Sapersson } 18313284Sapersson /* 18323284Sapersson * Copy router information 18333284Sapersson */ 18343284Sapersson router_list = pi->pi_router_list; 18353284Sapersson while (router_list != NULL) { 18363284Sapersson router.router_info_type = NDPD_ROUTER_INFO; 18373284Sapersson router.router_info_version = NDPD_ROUTER_INFO_VER; 18383284Sapersson router.router_address = router_list->dr_address; 18393284Sapersson router.router_lifetime = router_list->dr_lifetime; 18403284Sapersson router.router_phyint_index = pi->pi_index; 18413284Sapersson (void) sendto(mibsock, &router, sizeof (router), 0, 18423284Sapersson (struct sockaddr *)&from, fromlen); 18433284Sapersson router_list = router_list->dr_next; 18443284Sapersson } 18453284Sapersson } 18463284Sapersson } 18473284Sapersson 18480Sstevel@tonic-gate /* 18490Sstevel@tonic-gate * Look if the phyint or one of its prefixes have been removed from 18500Sstevel@tonic-gate * the kernel and take appropriate action. 18518485SPeter.Memishian@Sun.COM * Uses pr_in_use and pi{,_kernel}_state. 18520Sstevel@tonic-gate */ 18530Sstevel@tonic-gate static void 18540Sstevel@tonic-gate check_if_removed(struct phyint *pi) 18550Sstevel@tonic-gate { 18568485SPeter.Memishian@Sun.COM struct prefix *pr, *next_pr; 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate /* 18598485SPeter.Memishian@Sun.COM * Detect prefixes which are removed. 18608485SPeter.Memishian@Sun.COM * Static prefixes are just removed from our tables. 18618485SPeter.Memishian@Sun.COM * Non-static prefixes are recreated i.e. in.ndpd takes precedence 18628485SPeter.Memishian@Sun.COM * over manually removing prefixes via ifconfig. 18638485SPeter.Memishian@Sun.COM */ 18648485SPeter.Memishian@Sun.COM for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 18658485SPeter.Memishian@Sun.COM next_pr = pr->pr_next; 18668485SPeter.Memishian@Sun.COM if (!pr->pr_in_use) { 18678485SPeter.Memishian@Sun.COM /* Clear everything except PR_STATIC */ 18688485SPeter.Memishian@Sun.COM pr->pr_kernel_state &= PR_STATIC; 1869*12016SGirish.Moodalbail@Sun.COM if (pr->pr_state & PR_STATIC) 1870*12016SGirish.Moodalbail@Sun.COM prefix_update_ipadm_addrobj(pr, _B_FALSE); 18718485SPeter.Memishian@Sun.COM pr->pr_name[0] = '\0'; 18728485SPeter.Memishian@Sun.COM if (pr->pr_state & PR_STATIC) { 18738485SPeter.Memishian@Sun.COM prefix_delete(pr); 18748485SPeter.Memishian@Sun.COM } else if (!(pi->pi_kernel_state & PI_PRESENT)) { 18758485SPeter.Memishian@Sun.COM /* 18768485SPeter.Memishian@Sun.COM * Ensure that there are no future attempts to 18778485SPeter.Memishian@Sun.COM * run prefix_update_k since the phyint is gone. 18788485SPeter.Memishian@Sun.COM */ 18798485SPeter.Memishian@Sun.COM pr->pr_state = pr->pr_kernel_state; 18808485SPeter.Memishian@Sun.COM } else if (pr->pr_state != pr->pr_kernel_state) { 18818485SPeter.Memishian@Sun.COM logmsg(LOG_INFO, "Prefix manually removed " 18828485SPeter.Memishian@Sun.COM "on %s; recreating\n", pi->pi_name); 18838485SPeter.Memishian@Sun.COM prefix_update_k(pr); 18848485SPeter.Memishian@Sun.COM } 18858485SPeter.Memishian@Sun.COM } 18868485SPeter.Memishian@Sun.COM } 18878485SPeter.Memishian@Sun.COM 18888485SPeter.Memishian@Sun.COM /* 18898485SPeter.Memishian@Sun.COM * Detect phyints that have been removed from the kernel, and tear 18908485SPeter.Memishian@Sun.COM * down any prefixes we created that are associated with that phyint. 18918485SPeter.Memishian@Sun.COM * (NOTE: IPMP depends on in.ndpd tearing down these prefixes so an 18928485SPeter.Memishian@Sun.COM * administrator can easily place an IP interface with ADDRCONF'd 18938485SPeter.Memishian@Sun.COM * addresses into an IPMP group.) 18940Sstevel@tonic-gate */ 18950Sstevel@tonic-gate if (!(pi->pi_kernel_state & PI_PRESENT) && 18960Sstevel@tonic-gate (pi->pi_state & PI_PRESENT)) { 18970Sstevel@tonic-gate logmsg(LOG_ERR, "Interface %s has been removed from kernel. " 18980Sstevel@tonic-gate "in.ndpd will no longer use it\n", pi->pi_name); 18998485SPeter.Memishian@Sun.COM 19008485SPeter.Memishian@Sun.COM for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 19018485SPeter.Memishian@Sun.COM next_pr = pr->pr_next; 19028485SPeter.Memishian@Sun.COM if (pr->pr_state & PR_AUTO) 1903*12016SGirish.Moodalbail@Sun.COM prefix_update_ipadm_addrobj(pr, _B_FALSE); 19048485SPeter.Memishian@Sun.COM prefix_delete(pr); 19058485SPeter.Memishian@Sun.COM } 19068485SPeter.Memishian@Sun.COM 19070Sstevel@tonic-gate /* 19088485SPeter.Memishian@Sun.COM * Clear state so that should the phyint reappear we will 19098485SPeter.Memishian@Sun.COM * start with initial advertisements or solicitations. 19100Sstevel@tonic-gate */ 19110Sstevel@tonic-gate phyint_cleanup(pi); 19120Sstevel@tonic-gate } 19130Sstevel@tonic-gate } 19140Sstevel@tonic-gate 19150Sstevel@tonic-gate 19160Sstevel@tonic-gate /* 19170Sstevel@tonic-gate * Queuing mechanism for router advertisements that are sent by in.ndpd 19180Sstevel@tonic-gate * and that also need to be processed by in.ndpd. 19190Sstevel@tonic-gate * Uses "signal number" 255 to indicate to the main poll loop 19200Sstevel@tonic-gate * that there is something to dequeue and send to incomining_ra(). 19210Sstevel@tonic-gate */ 19220Sstevel@tonic-gate struct raq { 19230Sstevel@tonic-gate struct raq *raq_next; 19240Sstevel@tonic-gate struct phyint *raq_pi; 19250Sstevel@tonic-gate int raq_packetlen; 19260Sstevel@tonic-gate uchar_t *raq_packet; 19270Sstevel@tonic-gate }; 19280Sstevel@tonic-gate static struct raq *raq_head = NULL; 19290Sstevel@tonic-gate 19300Sstevel@tonic-gate /* 19310Sstevel@tonic-gate * Allocate a struct raq and memory for the packet. 19320Sstevel@tonic-gate * Send signal 255 to have poll dequeue. 19330Sstevel@tonic-gate */ 19340Sstevel@tonic-gate static void 19350Sstevel@tonic-gate loopback_ra_enqueue(struct phyint *pi, struct nd_router_advert *ra, int len) 19360Sstevel@tonic-gate { 19370Sstevel@tonic-gate struct raq *raq; 19380Sstevel@tonic-gate struct raq **raqp; 19390Sstevel@tonic-gate 19400Sstevel@tonic-gate if (no_loopback) 19410Sstevel@tonic-gate return; 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate if (debug & D_PKTOUT) 19440Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_enqueue for %s\n", pi->pi_name); 19450Sstevel@tonic-gate 19460Sstevel@tonic-gate raq = calloc(sizeof (struct raq), 1); 19470Sstevel@tonic-gate if (raq == NULL) { 19480Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 19490Sstevel@tonic-gate return; 19500Sstevel@tonic-gate } 19510Sstevel@tonic-gate raq->raq_packet = malloc(len); 19520Sstevel@tonic-gate if (raq->raq_packet == NULL) { 19530Sstevel@tonic-gate free(raq); 19540Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 19550Sstevel@tonic-gate return; 19560Sstevel@tonic-gate } 19570Sstevel@tonic-gate bcopy(ra, raq->raq_packet, len); 19580Sstevel@tonic-gate raq->raq_packetlen = len; 19590Sstevel@tonic-gate raq->raq_pi = pi; 19600Sstevel@tonic-gate 19610Sstevel@tonic-gate /* Tail insert */ 19620Sstevel@tonic-gate raqp = &raq_head; 19630Sstevel@tonic-gate while (*raqp != NULL) 19640Sstevel@tonic-gate raqp = &((*raqp)->raq_next); 19650Sstevel@tonic-gate *raqp = raq; 19660Sstevel@tonic-gate 19670Sstevel@tonic-gate /* Signal for poll loop */ 19680Sstevel@tonic-gate sig_handler(255); 19690Sstevel@tonic-gate } 19700Sstevel@tonic-gate 19710Sstevel@tonic-gate /* 19720Sstevel@tonic-gate * Dequeue and process all queued advertisements. 19730Sstevel@tonic-gate */ 19740Sstevel@tonic-gate static void 19750Sstevel@tonic-gate loopback_ra_dequeue(void) 19760Sstevel@tonic-gate { 19770Sstevel@tonic-gate struct sockaddr_in6 from = IN6ADDR_LOOPBACK_INIT; 19780Sstevel@tonic-gate struct raq *raq; 19790Sstevel@tonic-gate 19800Sstevel@tonic-gate if (debug & D_PKTIN) 19810Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue()\n"); 19820Sstevel@tonic-gate 19830Sstevel@tonic-gate while ((raq = raq_head) != NULL) { 19840Sstevel@tonic-gate raq_head = raq->raq_next; 19850Sstevel@tonic-gate raq->raq_next = NULL; 19860Sstevel@tonic-gate 19870Sstevel@tonic-gate if (debug & D_PKTIN) { 19880Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue for %s\n", 19890Sstevel@tonic-gate raq->raq_pi->pi_name); 19900Sstevel@tonic-gate } 19910Sstevel@tonic-gate 19920Sstevel@tonic-gate incoming_ra(raq->raq_pi, 19930Sstevel@tonic-gate (struct nd_router_advert *)raq->raq_packet, 19940Sstevel@tonic-gate raq->raq_packetlen, &from, _B_TRUE); 19950Sstevel@tonic-gate free(raq->raq_packet); 19960Sstevel@tonic-gate free(raq); 19970Sstevel@tonic-gate } 19980Sstevel@tonic-gate } 19990Sstevel@tonic-gate 20000Sstevel@tonic-gate 20010Sstevel@tonic-gate static void 20020Sstevel@tonic-gate usage(char *cmd) 20030Sstevel@tonic-gate { 20040Sstevel@tonic-gate (void) fprintf(stderr, 20050Sstevel@tonic-gate "usage: %s [ -adt ] [-f <config file>]\n", cmd); 20060Sstevel@tonic-gate } 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate int 20090Sstevel@tonic-gate main(int argc, char *argv[]) 20100Sstevel@tonic-gate { 20110Sstevel@tonic-gate int i; 20120Sstevel@tonic-gate struct phyint *pi; 20130Sstevel@tonic-gate int c; 20140Sstevel@tonic-gate char *config_file = PATH_NDPD_CONF; 20150Sstevel@tonic-gate boolean_t file_required = _B_FALSE; 20160Sstevel@tonic-gate 20170Sstevel@tonic-gate argv0 = argv; 20180Sstevel@tonic-gate srandom(gethostid()); 20190Sstevel@tonic-gate (void) umask(0022); 20200Sstevel@tonic-gate 20210Sstevel@tonic-gate while ((c = getopt(argc, argv, "adD:ntIf:")) != EOF) { 20220Sstevel@tonic-gate switch (c) { 20230Sstevel@tonic-gate case 'a': 20240Sstevel@tonic-gate /* 20250Sstevel@tonic-gate * The StatelessAddrConf variable in ndpd.conf, if 20260Sstevel@tonic-gate * present, will override this setting. 20270Sstevel@tonic-gate */ 20280Sstevel@tonic-gate ifdefaults[I_StatelessAddrConf].cf_value = 0; 20290Sstevel@tonic-gate break; 20300Sstevel@tonic-gate case 'd': 20310Sstevel@tonic-gate debug = D_ALL; 20320Sstevel@tonic-gate break; 20330Sstevel@tonic-gate case 'D': 20340Sstevel@tonic-gate i = strtol((char *)optarg, NULL, 0); 20350Sstevel@tonic-gate if (i == 0) { 20360Sstevel@tonic-gate (void) fprintf(stderr, "Bad debug flags: %s\n", 20370Sstevel@tonic-gate (char *)optarg); 20380Sstevel@tonic-gate exit(1); 20390Sstevel@tonic-gate } 20400Sstevel@tonic-gate debug |= i; 20410Sstevel@tonic-gate break; 20420Sstevel@tonic-gate case 'n': 20430Sstevel@tonic-gate no_loopback = 1; 20440Sstevel@tonic-gate break; 20450Sstevel@tonic-gate case 'I': 20460Sstevel@tonic-gate show_ifs = 1; 20470Sstevel@tonic-gate break; 20480Sstevel@tonic-gate case 't': 20490Sstevel@tonic-gate debug |= D_PKTIN | D_PKTOUT | D_PKTBAD; 20500Sstevel@tonic-gate break; 20510Sstevel@tonic-gate case 'f': 20520Sstevel@tonic-gate config_file = (char *)optarg; 20530Sstevel@tonic-gate file_required = _B_TRUE; 20540Sstevel@tonic-gate break; 20550Sstevel@tonic-gate case '?': 20560Sstevel@tonic-gate usage(argv[0]); 20570Sstevel@tonic-gate exit(1); 20580Sstevel@tonic-gate } 20590Sstevel@tonic-gate } 20600Sstevel@tonic-gate 20610Sstevel@tonic-gate if (parse_config(config_file, file_required) == -1) 20620Sstevel@tonic-gate exit(2); 20630Sstevel@tonic-gate 20640Sstevel@tonic-gate if (show_ifs) 20650Sstevel@tonic-gate phyint_print_all(); 20660Sstevel@tonic-gate 2067*12016SGirish.Moodalbail@Sun.COM if (debug == 0) 20680Sstevel@tonic-gate initlog(); 20690Sstevel@tonic-gate 2070*12016SGirish.Moodalbail@Sun.COM cmdsock = ndpd_setup_cmd_listener(); 20710Sstevel@tonic-gate setup_eventpipe(); 20720Sstevel@tonic-gate rtsock = setup_rtsock(); 20733284Sapersson mibsock = setup_mibsock(); 20740Sstevel@tonic-gate timer_init(); 20750Sstevel@tonic-gate initifs(_B_TRUE); 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate check_daemonize(); 20780Sstevel@tonic-gate 20790Sstevel@tonic-gate for (;;) { 20800Sstevel@tonic-gate if (poll(pollfds, pollfd_num, -1) < 0) { 20810Sstevel@tonic-gate if (errno == EINTR) 20820Sstevel@tonic-gate continue; 20830Sstevel@tonic-gate logperror("main: poll"); 20840Sstevel@tonic-gate exit(1); 20850Sstevel@tonic-gate } 20860Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 20870Sstevel@tonic-gate if (!(pollfds[i].revents & POLLIN)) 20880Sstevel@tonic-gate continue; 20890Sstevel@tonic-gate if (pollfds[i].fd == eventpipe_read) { 20900Sstevel@tonic-gate in_signal(eventpipe_read); 20910Sstevel@tonic-gate break; 20920Sstevel@tonic-gate } 20930Sstevel@tonic-gate if (pollfds[i].fd == rtsock) { 20940Sstevel@tonic-gate process_rtsock(rtsock); 20950Sstevel@tonic-gate break; 20960Sstevel@tonic-gate } 20973284Sapersson if (pollfds[i].fd == mibsock) { 20983284Sapersson process_mibsock(mibsock); 20993284Sapersson break; 21003284Sapersson } 2101*12016SGirish.Moodalbail@Sun.COM if (pollfds[i].fd == cmdsock) { 2102*12016SGirish.Moodalbail@Sun.COM ndpd_cmd_handler(cmdsock); 2103*12016SGirish.Moodalbail@Sun.COM break; 2104*12016SGirish.Moodalbail@Sun.COM } 21050Sstevel@tonic-gate /* 21060Sstevel@tonic-gate * Run timer routine to advance clock if more than 21070Sstevel@tonic-gate * half a second since the clock was advanced. 21080Sstevel@tonic-gate * This limits CPU usage under severe packet 21090Sstevel@tonic-gate * arrival rates but it creates a slight inaccuracy 21100Sstevel@tonic-gate * in the timer mechanism. 21110Sstevel@tonic-gate */ 21120Sstevel@tonic-gate conditional_run_timeouts(500U); 21130Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 21140Sstevel@tonic-gate if (pollfds[i].fd == pi->pi_sock) { 21150Sstevel@tonic-gate in_data(pi); 21160Sstevel@tonic-gate break; 21170Sstevel@tonic-gate } 21180Sstevel@tonic-gate } 21190Sstevel@tonic-gate } 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate /* NOTREACHED */ 21220Sstevel@tonic-gate return (0); 21230Sstevel@tonic-gate } 21240Sstevel@tonic-gate 21250Sstevel@tonic-gate /* 21260Sstevel@tonic-gate * LOGGER 21270Sstevel@tonic-gate */ 21280Sstevel@tonic-gate 21290Sstevel@tonic-gate static boolean_t logging = _B_FALSE; 21300Sstevel@tonic-gate 21310Sstevel@tonic-gate static void 21320Sstevel@tonic-gate initlog(void) 21330Sstevel@tonic-gate { 21340Sstevel@tonic-gate logging = _B_TRUE; 21350Sstevel@tonic-gate openlog("in.ndpd", LOG_PID | LOG_CONS, LOG_DAEMON); 21360Sstevel@tonic-gate } 21370Sstevel@tonic-gate 21380Sstevel@tonic-gate /* Print the date/time without a trailing carridge return */ 21390Sstevel@tonic-gate static void 21400Sstevel@tonic-gate fprintdate(FILE *file) 21410Sstevel@tonic-gate { 21420Sstevel@tonic-gate char buf[BUFSIZ]; 21430Sstevel@tonic-gate struct tm tms; 21440Sstevel@tonic-gate time_t now; 21450Sstevel@tonic-gate 21460Sstevel@tonic-gate now = time(NULL); 21470Sstevel@tonic-gate (void) localtime_r(&now, &tms); 21480Sstevel@tonic-gate (void) strftime(buf, sizeof (buf), "%h %d %X", &tms); 21490Sstevel@tonic-gate (void) fprintf(file, "%s ", buf); 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate 21522546Scarlsonj /* PRINTFLIKE2 */ 21530Sstevel@tonic-gate void 21542428Smh138676 logmsg(int level, const char *fmt, ...) 21550Sstevel@tonic-gate { 21560Sstevel@tonic-gate va_list ap; 21570Sstevel@tonic-gate va_start(ap, fmt); 21580Sstevel@tonic-gate 21590Sstevel@tonic-gate if (logging) { 21600Sstevel@tonic-gate vsyslog(level, fmt, ap); 21610Sstevel@tonic-gate } else { 21620Sstevel@tonic-gate fprintdate(stderr); 21630Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 21640Sstevel@tonic-gate } 21650Sstevel@tonic-gate va_end(ap); 21660Sstevel@tonic-gate } 21670Sstevel@tonic-gate 21680Sstevel@tonic-gate void 21692428Smh138676 logperror(const char *str) 21700Sstevel@tonic-gate { 21710Sstevel@tonic-gate if (logging) { 21720Sstevel@tonic-gate syslog(LOG_ERR, "%s: %m\n", str); 21730Sstevel@tonic-gate } else { 21740Sstevel@tonic-gate fprintdate(stderr); 21750Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 21760Sstevel@tonic-gate } 21770Sstevel@tonic-gate } 21780Sstevel@tonic-gate 21790Sstevel@tonic-gate void 21802428Smh138676 logperror_pi(const struct phyint *pi, const char *str) 21810Sstevel@tonic-gate { 21820Sstevel@tonic-gate if (logging) { 21830Sstevel@tonic-gate syslog(LOG_ERR, "%s (interface %s): %m\n", 21840Sstevel@tonic-gate str, pi->pi_name); 21850Sstevel@tonic-gate } else { 21860Sstevel@tonic-gate fprintdate(stderr); 21870Sstevel@tonic-gate (void) fprintf(stderr, "%s (interface %s): %s\n", 21880Sstevel@tonic-gate str, pi->pi_name, strerror(errno)); 21890Sstevel@tonic-gate } 21900Sstevel@tonic-gate } 21910Sstevel@tonic-gate 21920Sstevel@tonic-gate void 21932428Smh138676 logperror_pr(const struct prefix *pr, const char *str) 21940Sstevel@tonic-gate { 21950Sstevel@tonic-gate if (logging) { 21960Sstevel@tonic-gate syslog(LOG_ERR, "%s (prefix %s if %s): %m\n", 21970Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name); 21980Sstevel@tonic-gate } else { 21990Sstevel@tonic-gate fprintdate(stderr); 22000Sstevel@tonic-gate (void) fprintf(stderr, "%s (prefix %s if %s): %s\n", 22010Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name, 22020Sstevel@tonic-gate strerror(errno)); 22030Sstevel@tonic-gate } 22040Sstevel@tonic-gate } 2205*12016SGirish.Moodalbail@Sun.COM 2206*12016SGirish.Moodalbail@Sun.COM static int 2207*12016SGirish.Moodalbail@Sun.COM ndpd_setup_cmd_listener(void) 2208*12016SGirish.Moodalbail@Sun.COM { 2209*12016SGirish.Moodalbail@Sun.COM int sock; 2210*12016SGirish.Moodalbail@Sun.COM int ret; 2211*12016SGirish.Moodalbail@Sun.COM struct sockaddr_un servaddr; 2212*12016SGirish.Moodalbail@Sun.COM 2213*12016SGirish.Moodalbail@Sun.COM sock = socket(AF_UNIX, SOCK_STREAM, 0); 2214*12016SGirish.Moodalbail@Sun.COM if (sock < 0) { 2215*12016SGirish.Moodalbail@Sun.COM logperror("socket"); 2216*12016SGirish.Moodalbail@Sun.COM exit(1); 2217*12016SGirish.Moodalbail@Sun.COM } 2218*12016SGirish.Moodalbail@Sun.COM 2219*12016SGirish.Moodalbail@Sun.COM bzero(&servaddr, sizeof (servaddr)); 2220*12016SGirish.Moodalbail@Sun.COM servaddr.sun_family = AF_UNIX; 2221*12016SGirish.Moodalbail@Sun.COM (void) strlcpy(servaddr.sun_path, IPADM_UDS_PATH, 2222*12016SGirish.Moodalbail@Sun.COM sizeof (servaddr.sun_path)); 2223*12016SGirish.Moodalbail@Sun.COM (void) unlink(servaddr.sun_path); 2224*12016SGirish.Moodalbail@Sun.COM ret = bind(sock, (struct sockaddr *)&servaddr, sizeof (servaddr)); 2225*12016SGirish.Moodalbail@Sun.COM if (ret < 0) { 2226*12016SGirish.Moodalbail@Sun.COM logperror("bind"); 2227*12016SGirish.Moodalbail@Sun.COM exit(1); 2228*12016SGirish.Moodalbail@Sun.COM } 2229*12016SGirish.Moodalbail@Sun.COM if (listen(sock, 30) < 0) { 2230*12016SGirish.Moodalbail@Sun.COM logperror("listen"); 2231*12016SGirish.Moodalbail@Sun.COM exit(1); 2232*12016SGirish.Moodalbail@Sun.COM } 2233*12016SGirish.Moodalbail@Sun.COM if (poll_add(sock) == -1) { 2234*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "command socket could not be added to the " 2235*12016SGirish.Moodalbail@Sun.COM "polling set\n"); 2236*12016SGirish.Moodalbail@Sun.COM exit(1); 2237*12016SGirish.Moodalbail@Sun.COM } 2238*12016SGirish.Moodalbail@Sun.COM 2239*12016SGirish.Moodalbail@Sun.COM return (sock); 2240*12016SGirish.Moodalbail@Sun.COM } 2241*12016SGirish.Moodalbail@Sun.COM 2242*12016SGirish.Moodalbail@Sun.COM /* 2243*12016SGirish.Moodalbail@Sun.COM * Commands received over the command socket come here 2244*12016SGirish.Moodalbail@Sun.COM */ 2245*12016SGirish.Moodalbail@Sun.COM static void 2246*12016SGirish.Moodalbail@Sun.COM ndpd_cmd_handler(int sock) 2247*12016SGirish.Moodalbail@Sun.COM { 2248*12016SGirish.Moodalbail@Sun.COM int newfd; 2249*12016SGirish.Moodalbail@Sun.COM struct sockaddr_storage peer; 2250*12016SGirish.Moodalbail@Sun.COM socklen_t peerlen; 2251*12016SGirish.Moodalbail@Sun.COM ipadm_ndpd_msg_t ndpd_msg; 2252*12016SGirish.Moodalbail@Sun.COM int retval; 2253*12016SGirish.Moodalbail@Sun.COM 2254*12016SGirish.Moodalbail@Sun.COM peerlen = sizeof (peer); 2255*12016SGirish.Moodalbail@Sun.COM newfd = accept(sock, (struct sockaddr *)&peer, &peerlen); 2256*12016SGirish.Moodalbail@Sun.COM if (newfd < 0) { 2257*12016SGirish.Moodalbail@Sun.COM logperror("accept"); 2258*12016SGirish.Moodalbail@Sun.COM return; 2259*12016SGirish.Moodalbail@Sun.COM } 2260*12016SGirish.Moodalbail@Sun.COM 2261*12016SGirish.Moodalbail@Sun.COM retval = ipadm_ndpd_read(newfd, &ndpd_msg, sizeof (ndpd_msg)); 2262*12016SGirish.Moodalbail@Sun.COM if (retval != 0) 2263*12016SGirish.Moodalbail@Sun.COM logperror("Could not read ndpd command"); 2264*12016SGirish.Moodalbail@Sun.COM 2265*12016SGirish.Moodalbail@Sun.COM retval = ndpd_process_cmd(newfd, &ndpd_msg); 2266*12016SGirish.Moodalbail@Sun.COM if (retval != 0) { 2267*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "ndpd command on interface %s failed with " 2268*12016SGirish.Moodalbail@Sun.COM "error %s\n", ndpd_msg.inm_ifname, strerror(retval)); 2269*12016SGirish.Moodalbail@Sun.COM } 2270*12016SGirish.Moodalbail@Sun.COM (void) close(newfd); 2271*12016SGirish.Moodalbail@Sun.COM } 2272*12016SGirish.Moodalbail@Sun.COM 2273*12016SGirish.Moodalbail@Sun.COM /* 2274*12016SGirish.Moodalbail@Sun.COM * Process the commands received from the cmd listener socket. 2275*12016SGirish.Moodalbail@Sun.COM */ 2276*12016SGirish.Moodalbail@Sun.COM static int 2277*12016SGirish.Moodalbail@Sun.COM ndpd_process_cmd(int newfd, ipadm_ndpd_msg_t *msg) 2278*12016SGirish.Moodalbail@Sun.COM { 2279*12016SGirish.Moodalbail@Sun.COM int err; 2280*12016SGirish.Moodalbail@Sun.COM 2281*12016SGirish.Moodalbail@Sun.COM if (!ipadm_check_auth()) { 2282*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "User not authorized to send the command\n"); 2283*12016SGirish.Moodalbail@Sun.COM (void) ndpd_send_error(newfd, EPERM); 2284*12016SGirish.Moodalbail@Sun.COM return (EPERM); 2285*12016SGirish.Moodalbail@Sun.COM } 2286*12016SGirish.Moodalbail@Sun.COM switch (msg->inm_cmd) { 2287*12016SGirish.Moodalbail@Sun.COM case IPADM_DISABLE_AUTOCONF: 2288*12016SGirish.Moodalbail@Sun.COM err = ndpd_set_autoconf(msg->inm_ifname, _B_FALSE); 2289*12016SGirish.Moodalbail@Sun.COM break; 2290*12016SGirish.Moodalbail@Sun.COM 2291*12016SGirish.Moodalbail@Sun.COM case IPADM_ENABLE_AUTOCONF: 2292*12016SGirish.Moodalbail@Sun.COM err = ndpd_set_autoconf(msg->inm_ifname, _B_TRUE); 2293*12016SGirish.Moodalbail@Sun.COM break; 2294*12016SGirish.Moodalbail@Sun.COM 2295*12016SGirish.Moodalbail@Sun.COM case IPADM_CREATE_ADDRS: 2296*12016SGirish.Moodalbail@Sun.COM err = ndpd_create_addrs(msg->inm_ifname, msg->inm_intfid, 2297*12016SGirish.Moodalbail@Sun.COM msg->inm_intfidlen, msg->inm_stateless, 2298*12016SGirish.Moodalbail@Sun.COM msg->inm_stateful, msg->inm_aobjname); 2299*12016SGirish.Moodalbail@Sun.COM break; 2300*12016SGirish.Moodalbail@Sun.COM 2301*12016SGirish.Moodalbail@Sun.COM case IPADM_DELETE_ADDRS: 2302*12016SGirish.Moodalbail@Sun.COM err = ndpd_delete_addrs(msg->inm_ifname); 2303*12016SGirish.Moodalbail@Sun.COM break; 2304*12016SGirish.Moodalbail@Sun.COM 2305*12016SGirish.Moodalbail@Sun.COM default: 2306*12016SGirish.Moodalbail@Sun.COM err = EINVAL; 2307*12016SGirish.Moodalbail@Sun.COM break; 2308*12016SGirish.Moodalbail@Sun.COM } 2309*12016SGirish.Moodalbail@Sun.COM 2310*12016SGirish.Moodalbail@Sun.COM (void) ndpd_send_error(newfd, err); 2311*12016SGirish.Moodalbail@Sun.COM 2312*12016SGirish.Moodalbail@Sun.COM return (err); 2313*12016SGirish.Moodalbail@Sun.COM } 2314*12016SGirish.Moodalbail@Sun.COM 2315*12016SGirish.Moodalbail@Sun.COM static int 2316*12016SGirish.Moodalbail@Sun.COM ndpd_send_error(int fd, int error) 2317*12016SGirish.Moodalbail@Sun.COM { 2318*12016SGirish.Moodalbail@Sun.COM return (ipadm_ndpd_write(fd, &error, sizeof (error))); 2319*12016SGirish.Moodalbail@Sun.COM } 2320*12016SGirish.Moodalbail@Sun.COM 2321*12016SGirish.Moodalbail@Sun.COM /* 2322*12016SGirish.Moodalbail@Sun.COM * Disables/Enables autoconfiguration of addresses on the 2323*12016SGirish.Moodalbail@Sun.COM * given physical interface. 2324*12016SGirish.Moodalbail@Sun.COM * This is provided to support the legacy method of configuring IPv6 2325*12016SGirish.Moodalbail@Sun.COM * addresses. i.e. `ifconfig bge0 inet6 plumb` will plumb the interface 2326*12016SGirish.Moodalbail@Sun.COM * and start stateless and stateful autoconfiguration. If this function is 2327*12016SGirish.Moodalbail@Sun.COM * not called with enable=_B_FALSE, no autoconfiguration will be done until 2328*12016SGirish.Moodalbail@Sun.COM * ndpd_create_addrs() is called with an Interface ID. 2329*12016SGirish.Moodalbail@Sun.COM */ 2330*12016SGirish.Moodalbail@Sun.COM static int 2331*12016SGirish.Moodalbail@Sun.COM ndpd_set_autoconf(const char *ifname, boolean_t enable) 2332*12016SGirish.Moodalbail@Sun.COM { 2333*12016SGirish.Moodalbail@Sun.COM struct phyint *pi; 2334*12016SGirish.Moodalbail@Sun.COM 2335*12016SGirish.Moodalbail@Sun.COM pi = phyint_lookup((char *)ifname); 2336*12016SGirish.Moodalbail@Sun.COM if (pi == NULL) { 2337*12016SGirish.Moodalbail@Sun.COM /* 2338*12016SGirish.Moodalbail@Sun.COM * If the physical interface was plumbed but no 2339*12016SGirish.Moodalbail@Sun.COM * addresses were configured yet, phyint will not exist. 2340*12016SGirish.Moodalbail@Sun.COM */ 2341*12016SGirish.Moodalbail@Sun.COM pi = phyint_create((char *)ifname); 2342*12016SGirish.Moodalbail@Sun.COM if (pi == NULL) { 2343*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "could not create phyint for " 2344*12016SGirish.Moodalbail@Sun.COM "interface %s", ifname); 2345*12016SGirish.Moodalbail@Sun.COM return (ENOMEM); 2346*12016SGirish.Moodalbail@Sun.COM } 2347*12016SGirish.Moodalbail@Sun.COM } 2348*12016SGirish.Moodalbail@Sun.COM pi->pi_autoconf = enable; 2349*12016SGirish.Moodalbail@Sun.COM 2350*12016SGirish.Moodalbail@Sun.COM if (debug & D_PHYINT) { 2351*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_DEBUG, "ndpd_set_autoconf: %s autoconf for " 2352*12016SGirish.Moodalbail@Sun.COM "interface %s\n", (enable ? "enabled" : "disabled"), 2353*12016SGirish.Moodalbail@Sun.COM pi->pi_name); 2354*12016SGirish.Moodalbail@Sun.COM } 2355*12016SGirish.Moodalbail@Sun.COM return (0); 2356*12016SGirish.Moodalbail@Sun.COM } 2357*12016SGirish.Moodalbail@Sun.COM 2358*12016SGirish.Moodalbail@Sun.COM /* 2359*12016SGirish.Moodalbail@Sun.COM * Create auto-configured addresses on the given interface using 2360*12016SGirish.Moodalbail@Sun.COM * the given token as the interface id during the next Router Advertisement. 2361*12016SGirish.Moodalbail@Sun.COM * Currently, only one token per interface is supported. 2362*12016SGirish.Moodalbail@Sun.COM */ 2363*12016SGirish.Moodalbail@Sun.COM static int 2364*12016SGirish.Moodalbail@Sun.COM ndpd_create_addrs(const char *ifname, struct sockaddr_in6 intfid, int intfidlen, 2365*12016SGirish.Moodalbail@Sun.COM boolean_t stateless, boolean_t stateful, char *addrobj) 2366*12016SGirish.Moodalbail@Sun.COM { 2367*12016SGirish.Moodalbail@Sun.COM struct phyint *pi; 2368*12016SGirish.Moodalbail@Sun.COM struct lifreq lifr; 2369*12016SGirish.Moodalbail@Sun.COM struct sockaddr_in6 *sin6; 2370*12016SGirish.Moodalbail@Sun.COM int err; 2371*12016SGirish.Moodalbail@Sun.COM 2372*12016SGirish.Moodalbail@Sun.COM pi = phyint_lookup((char *)ifname); 2373*12016SGirish.Moodalbail@Sun.COM if (pi == NULL) { 2374*12016SGirish.Moodalbail@Sun.COM /* 2375*12016SGirish.Moodalbail@Sun.COM * If the physical interface was plumbed but no 2376*12016SGirish.Moodalbail@Sun.COM * addresses were configured yet, phyint will not exist. 2377*12016SGirish.Moodalbail@Sun.COM */ 2378*12016SGirish.Moodalbail@Sun.COM pi = phyint_create((char *)ifname); 2379*12016SGirish.Moodalbail@Sun.COM if (pi == NULL) { 2380*12016SGirish.Moodalbail@Sun.COM if (debug & D_PHYINT) 2381*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "could not create phyint " 2382*12016SGirish.Moodalbail@Sun.COM "for interface %s", ifname); 2383*12016SGirish.Moodalbail@Sun.COM return (ENOMEM); 2384*12016SGirish.Moodalbail@Sun.COM } 2385*12016SGirish.Moodalbail@Sun.COM } else if (pi->pi_autoconf) { 2386*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "autoconfiguration already in progress\n"); 2387*12016SGirish.Moodalbail@Sun.COM return (EEXIST); 2388*12016SGirish.Moodalbail@Sun.COM } 2389*12016SGirish.Moodalbail@Sun.COM check_autoconf_var_consistency(pi, stateless, stateful); 2390*12016SGirish.Moodalbail@Sun.COM 2391*12016SGirish.Moodalbail@Sun.COM if (intfidlen == 0) { 2392*12016SGirish.Moodalbail@Sun.COM pi->pi_default_token = _B_TRUE; 2393*12016SGirish.Moodalbail@Sun.COM if (ifsock < 0) { 2394*12016SGirish.Moodalbail@Sun.COM ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 2395*12016SGirish.Moodalbail@Sun.COM if (ifsock < 0) { 2396*12016SGirish.Moodalbail@Sun.COM err = errno; 2397*12016SGirish.Moodalbail@Sun.COM logperror("ndpd_create_addrs: socket"); 2398*12016SGirish.Moodalbail@Sun.COM return (err); 2399*12016SGirish.Moodalbail@Sun.COM } 2400*12016SGirish.Moodalbail@Sun.COM } 2401*12016SGirish.Moodalbail@Sun.COM (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2402*12016SGirish.Moodalbail@Sun.COM sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 2403*12016SGirish.Moodalbail@Sun.COM if (ioctl(ifsock, SIOCGLIFTOKEN, (char *)&lifr) < 0) { 2404*12016SGirish.Moodalbail@Sun.COM err = errno; 2405*12016SGirish.Moodalbail@Sun.COM logperror("SIOCGLIFTOKEN"); 2406*12016SGirish.Moodalbail@Sun.COM return (err); 2407*12016SGirish.Moodalbail@Sun.COM } 2408*12016SGirish.Moodalbail@Sun.COM pi->pi_token = sin6->sin6_addr; 2409*12016SGirish.Moodalbail@Sun.COM pi->pi_token_length = lifr.lifr_addrlen; 2410*12016SGirish.Moodalbail@Sun.COM } else { 2411*12016SGirish.Moodalbail@Sun.COM pi->pi_default_token = _B_FALSE; 2412*12016SGirish.Moodalbail@Sun.COM pi->pi_token = intfid.sin6_addr; 2413*12016SGirish.Moodalbail@Sun.COM pi->pi_token_length = intfidlen; 2414*12016SGirish.Moodalbail@Sun.COM } 2415*12016SGirish.Moodalbail@Sun.COM pi->pi_stateless = stateless; 2416*12016SGirish.Moodalbail@Sun.COM pi->pi_stateful = stateful; 2417*12016SGirish.Moodalbail@Sun.COM (void) strlcpy(pi->pi_ipadm_aobjname, addrobj, 2418*12016SGirish.Moodalbail@Sun.COM sizeof (pi->pi_ipadm_aobjname)); 2419*12016SGirish.Moodalbail@Sun.COM 2420*12016SGirish.Moodalbail@Sun.COM /* We can allow autoconfiguration now. */ 2421*12016SGirish.Moodalbail@Sun.COM pi->pi_autoconf = _B_TRUE; 2422*12016SGirish.Moodalbail@Sun.COM 2423*12016SGirish.Moodalbail@Sun.COM /* Restart the solicitations. */ 2424*12016SGirish.Moodalbail@Sun.COM if (pi->pi_sol_state == DONE_SOLICIT) 2425*12016SGirish.Moodalbail@Sun.COM pi->pi_sol_state = NO_SOLICIT; 2426*12016SGirish.Moodalbail@Sun.COM if (pi->pi_sol_state == NO_SOLICIT) 2427*12016SGirish.Moodalbail@Sun.COM check_to_solicit(pi, START_INIT_SOLICIT); 2428*12016SGirish.Moodalbail@Sun.COM if (debug & D_PHYINT) 2429*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_DEBUG, "ndpd_create_addrs: " 2430*12016SGirish.Moodalbail@Sun.COM "added token to interface %s\n", pi->pi_name); 2431*12016SGirish.Moodalbail@Sun.COM return (0); 2432*12016SGirish.Moodalbail@Sun.COM } 2433*12016SGirish.Moodalbail@Sun.COM 2434*12016SGirish.Moodalbail@Sun.COM /* 2435*12016SGirish.Moodalbail@Sun.COM * This function deletes all addresses on the given interface 2436*12016SGirish.Moodalbail@Sun.COM * with the given Interface ID. 2437*12016SGirish.Moodalbail@Sun.COM */ 2438*12016SGirish.Moodalbail@Sun.COM static int 2439*12016SGirish.Moodalbail@Sun.COM ndpd_delete_addrs(const char *ifname) 2440*12016SGirish.Moodalbail@Sun.COM { 2441*12016SGirish.Moodalbail@Sun.COM struct phyint *pi; 2442*12016SGirish.Moodalbail@Sun.COM struct prefix *pr, *next_pr; 2443*12016SGirish.Moodalbail@Sun.COM struct lifreq lifr; 2444*12016SGirish.Moodalbail@Sun.COM int err; 2445*12016SGirish.Moodalbail@Sun.COM 2446*12016SGirish.Moodalbail@Sun.COM pi = phyint_lookup((char *)ifname); 2447*12016SGirish.Moodalbail@Sun.COM if (pi == NULL) { 2448*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "no phyint found for %s", ifname); 2449*12016SGirish.Moodalbail@Sun.COM return (ENXIO); 2450*12016SGirish.Moodalbail@Sun.COM } 2451*12016SGirish.Moodalbail@Sun.COM if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_token)) { 2452*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "token does not exist for %s", ifname); 2453*12016SGirish.Moodalbail@Sun.COM return (EINVAL); 2454*12016SGirish.Moodalbail@Sun.COM } 2455*12016SGirish.Moodalbail@Sun.COM 2456*12016SGirish.Moodalbail@Sun.COM if (ifsock < 0) { 2457*12016SGirish.Moodalbail@Sun.COM ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 2458*12016SGirish.Moodalbail@Sun.COM if (ifsock < 0) { 2459*12016SGirish.Moodalbail@Sun.COM err = errno; 2460*12016SGirish.Moodalbail@Sun.COM logperror("ndpd_create_addrs: socket"); 2461*12016SGirish.Moodalbail@Sun.COM return (err); 2462*12016SGirish.Moodalbail@Sun.COM } 2463*12016SGirish.Moodalbail@Sun.COM } 2464*12016SGirish.Moodalbail@Sun.COM /* Remove the prefixes for this phyint if they exist */ 2465*12016SGirish.Moodalbail@Sun.COM for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 2466*12016SGirish.Moodalbail@Sun.COM next_pr = pr->pr_next; 2467*12016SGirish.Moodalbail@Sun.COM if (pr->pr_name[0] == '\0') { 2468*12016SGirish.Moodalbail@Sun.COM prefix_delete(pr); 2469*12016SGirish.Moodalbail@Sun.COM continue; 2470*12016SGirish.Moodalbail@Sun.COM } 2471*12016SGirish.Moodalbail@Sun.COM /* 2472*12016SGirish.Moodalbail@Sun.COM * Delete all the prefixes for the auto-configured 2473*12016SGirish.Moodalbail@Sun.COM * addresses as well as the DHCPv6 addresses. 2474*12016SGirish.Moodalbail@Sun.COM */ 2475*12016SGirish.Moodalbail@Sun.COM (void) strncpy(lifr.lifr_name, pr->pr_name, 2476*12016SGirish.Moodalbail@Sun.COM sizeof (lifr.lifr_name)); 2477*12016SGirish.Moodalbail@Sun.COM if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 2478*12016SGirish.Moodalbail@Sun.COM err = errno; 2479*12016SGirish.Moodalbail@Sun.COM logperror("SIOCGLIFFLAGS"); 2480*12016SGirish.Moodalbail@Sun.COM return (err); 2481*12016SGirish.Moodalbail@Sun.COM } 2482*12016SGirish.Moodalbail@Sun.COM if ((lifr.lifr_flags & IFF_ADDRCONF) || 2483*12016SGirish.Moodalbail@Sun.COM (lifr.lifr_flags & IFF_DHCPRUNNING)) { 2484*12016SGirish.Moodalbail@Sun.COM prefix_update_ipadm_addrobj(pr, _B_FALSE); 2485*12016SGirish.Moodalbail@Sun.COM } 2486*12016SGirish.Moodalbail@Sun.COM prefix_delete(pr); 2487*12016SGirish.Moodalbail@Sun.COM } 2488*12016SGirish.Moodalbail@Sun.COM 2489*12016SGirish.Moodalbail@Sun.COM /* 2490*12016SGirish.Moodalbail@Sun.COM * If we had started dhcpagent, we need to release the leases 2491*12016SGirish.Moodalbail@Sun.COM * if any are required. 2492*12016SGirish.Moodalbail@Sun.COM */ 2493*12016SGirish.Moodalbail@Sun.COM if (pi->pi_stateful) { 2494*12016SGirish.Moodalbail@Sun.COM (void) strncpy(lifr.lifr_name, pi->pi_name, 2495*12016SGirish.Moodalbail@Sun.COM sizeof (lifr.lifr_name)); 2496*12016SGirish.Moodalbail@Sun.COM if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 2497*12016SGirish.Moodalbail@Sun.COM err = errno; 2498*12016SGirish.Moodalbail@Sun.COM logperror("SIOCGLIFFLAGS"); 2499*12016SGirish.Moodalbail@Sun.COM return (err); 2500*12016SGirish.Moodalbail@Sun.COM } 2501*12016SGirish.Moodalbail@Sun.COM if (lifr.lifr_flags & IFF_DHCPRUNNING) 2502*12016SGirish.Moodalbail@Sun.COM release_dhcp(pi); 2503*12016SGirish.Moodalbail@Sun.COM } 2504*12016SGirish.Moodalbail@Sun.COM 2505*12016SGirish.Moodalbail@Sun.COM /* 2506*12016SGirish.Moodalbail@Sun.COM * Reset the Interface ID on this phyint and stop autoconfigurations 2507*12016SGirish.Moodalbail@Sun.COM * until a new interface ID is provided. 2508*12016SGirish.Moodalbail@Sun.COM */ 2509*12016SGirish.Moodalbail@Sun.COM pi->pi_token = in6addr_any; 2510*12016SGirish.Moodalbail@Sun.COM pi->pi_token_length = 0; 2511*12016SGirish.Moodalbail@Sun.COM pi->pi_autoconf = _B_FALSE; 2512*12016SGirish.Moodalbail@Sun.COM pi->pi_ipadm_aobjname[0] = '\0'; 2513*12016SGirish.Moodalbail@Sun.COM 2514*12016SGirish.Moodalbail@Sun.COM /* Reset the stateless and stateful settings to default. */ 2515*12016SGirish.Moodalbail@Sun.COM pi->pi_stateless = pi->pi_StatelessAddrConf; 2516*12016SGirish.Moodalbail@Sun.COM pi->pi_stateful = pi->pi_StatefulAddrConf; 2517*12016SGirish.Moodalbail@Sun.COM 2518*12016SGirish.Moodalbail@Sun.COM if (debug & D_PHYINT) { 2519*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_DEBUG, "ndpd_delete_addrs: " 2520*12016SGirish.Moodalbail@Sun.COM "removed token from interface %s\n", pi->pi_name); 2521*12016SGirish.Moodalbail@Sun.COM } 2522*12016SGirish.Moodalbail@Sun.COM return (0); 2523*12016SGirish.Moodalbail@Sun.COM } 2524*12016SGirish.Moodalbail@Sun.COM 2525*12016SGirish.Moodalbail@Sun.COM void 2526*12016SGirish.Moodalbail@Sun.COM check_autoconf_var_consistency(struct phyint *pi, boolean_t stateless, 2527*12016SGirish.Moodalbail@Sun.COM boolean_t stateful) 2528*12016SGirish.Moodalbail@Sun.COM { 2529*12016SGirish.Moodalbail@Sun.COM /* 2530*12016SGirish.Moodalbail@Sun.COM * If StatelessAddrConf and StatelessAddrConf are set in 2531*12016SGirish.Moodalbail@Sun.COM * /etc/inet/ndpd.conf, check if the new values override those 2532*12016SGirish.Moodalbail@Sun.COM * settings. If so, log a warning. 2533*12016SGirish.Moodalbail@Sun.COM */ 2534*12016SGirish.Moodalbail@Sun.COM if ((pi->pi_StatelessAddrConf != 2535*12016SGirish.Moodalbail@Sun.COM ifdefaults[I_StatelessAddrConf].cf_value && 2536*12016SGirish.Moodalbail@Sun.COM stateless != pi->pi_StatelessAddrConf) || 2537*12016SGirish.Moodalbail@Sun.COM (pi->pi_StatefulAddrConf != 2538*12016SGirish.Moodalbail@Sun.COM ifdefaults[I_StatefulAddrConf].cf_value && 2539*12016SGirish.Moodalbail@Sun.COM stateful != pi->pi_StatefulAddrConf)) { 2540*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "check_autoconf_var_consistency: " 2541*12016SGirish.Moodalbail@Sun.COM "Overriding the StatelessAddrConf or StatefulAddrConf " 2542*12016SGirish.Moodalbail@Sun.COM "settings in ndpd.conf with the new values for " 2543*12016SGirish.Moodalbail@Sun.COM "interface %s\n", pi->pi_name); 2544*12016SGirish.Moodalbail@Sun.COM } 2545*12016SGirish.Moodalbail@Sun.COM } 2546*12016SGirish.Moodalbail@Sun.COM 2547*12016SGirish.Moodalbail@Sun.COM /* 2548*12016SGirish.Moodalbail@Sun.COM * If ipadm was used to start autoconfiguration and in.ndpd was restarted 2549*12016SGirish.Moodalbail@Sun.COM * for some reason, in.ndpd has to resume autoconfiguration when it comes up. 2550*12016SGirish.Moodalbail@Sun.COM * In this function, it scans the ipadm_addr_info() output to find a link-local 2551*12016SGirish.Moodalbail@Sun.COM * on this interface with address type "addrconf" and extracts the interface id. 2552*12016SGirish.Moodalbail@Sun.COM * It also stores the addrobj name to be used later when new addresses are 2553*12016SGirish.Moodalbail@Sun.COM * created for the prefixes advertised by the router. 2554*12016SGirish.Moodalbail@Sun.COM * If autoconfiguration was never started on this interface before in.ndpd 2555*12016SGirish.Moodalbail@Sun.COM * was killed, then in.ndpd should refrain from configuring prefixes, even if 2556*12016SGirish.Moodalbail@Sun.COM * there is a valid link-local on this interface, created by ipadm (identified 2557*12016SGirish.Moodalbail@Sun.COM * if there is a valid addrobj name). 2558*12016SGirish.Moodalbail@Sun.COM */ 2559*12016SGirish.Moodalbail@Sun.COM static int 2560*12016SGirish.Moodalbail@Sun.COM phyint_check_ipadm_intfid(struct phyint *pi) 2561*12016SGirish.Moodalbail@Sun.COM { 2562*12016SGirish.Moodalbail@Sun.COM ipadm_status_t status; 2563*12016SGirish.Moodalbail@Sun.COM ipadm_addr_info_t *addrinfo; 2564*12016SGirish.Moodalbail@Sun.COM struct ifaddrs *ifap; 2565*12016SGirish.Moodalbail@Sun.COM ipadm_addr_info_t *ainfop; 2566*12016SGirish.Moodalbail@Sun.COM struct sockaddr_in6 *sin6; 2567*12016SGirish.Moodalbail@Sun.COM ipadm_handle_t iph; 2568*12016SGirish.Moodalbail@Sun.COM 2569*12016SGirish.Moodalbail@Sun.COM if (ipadm_open(&iph, 0) != IPADM_SUCCESS) { 2570*12016SGirish.Moodalbail@Sun.COM logmsg(LOG_ERR, "could not open handle to libipadm\n"); 2571*12016SGirish.Moodalbail@Sun.COM return (-1); 2572*12016SGirish.Moodalbail@Sun.COM } 2573*12016SGirish.Moodalbail@Sun.COM 2574*12016SGirish.Moodalbail@Sun.COM status = ipadm_addr_info(iph, pi->pi_name, &addrinfo, 2575*12016SGirish.Moodalbail@Sun.COM IPADM_OPT_ZEROADDR, LIFC_NOXMIT|LIFC_TEMPORARY); 2576*12016SGirish.Moodalbail@Sun.COM if (status != IPADM_SUCCESS) { 2577*12016SGirish.Moodalbail@Sun.COM ipadm_close(iph); 2578*12016SGirish.Moodalbail@Sun.COM return (-1); 2579*12016SGirish.Moodalbail@Sun.COM } 2580*12016SGirish.Moodalbail@Sun.COM pi->pi_autoconf = _B_TRUE; 2581*12016SGirish.Moodalbail@Sun.COM for (ainfop = addrinfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) { 2582*12016SGirish.Moodalbail@Sun.COM ifap = &ainfop->ia_ifa; 2583*12016SGirish.Moodalbail@Sun.COM if (ifap->ifa_addr->ss_family != AF_INET6 || 2584*12016SGirish.Moodalbail@Sun.COM ainfop->ia_state == IFA_DISABLED) 2585*12016SGirish.Moodalbail@Sun.COM continue; 2586*12016SGirish.Moodalbail@Sun.COM sin6 = (struct sockaddr_in6 *)ifap->ifa_addr; 2587*12016SGirish.Moodalbail@Sun.COM if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 2588*12016SGirish.Moodalbail@Sun.COM if (ainfop->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) { 2589*12016SGirish.Moodalbail@Sun.COM pi->pi_token = sin6->sin6_addr; 2590*12016SGirish.Moodalbail@Sun.COM pi->pi_token._S6_un._S6_u32[0] = 0; 2591*12016SGirish.Moodalbail@Sun.COM pi->pi_token._S6_un._S6_u32[1] = 0; 2592*12016SGirish.Moodalbail@Sun.COM pi->pi_autoconf = _B_TRUE; 2593*12016SGirish.Moodalbail@Sun.COM (void) strlcpy(pi->pi_ipadm_aobjname, 2594*12016SGirish.Moodalbail@Sun.COM ainfop->ia_aobjname, 2595*12016SGirish.Moodalbail@Sun.COM sizeof (pi->pi_ipadm_aobjname)); 2596*12016SGirish.Moodalbail@Sun.COM break; 2597*12016SGirish.Moodalbail@Sun.COM } 2598*12016SGirish.Moodalbail@Sun.COM /* 2599*12016SGirish.Moodalbail@Sun.COM * If IFF_NOLINKLOCAL is set, then the link-local 2600*12016SGirish.Moodalbail@Sun.COM * was created using ipadm. Do not autoconfigure until 2601*12016SGirish.Moodalbail@Sun.COM * ipadm is explicitly used for autoconfiguration. 2602*12016SGirish.Moodalbail@Sun.COM */ 2603*12016SGirish.Moodalbail@Sun.COM if (ifap->ifa_flags & IFF_NOLINKLOCAL) 2604*12016SGirish.Moodalbail@Sun.COM pi->pi_autoconf = _B_FALSE; 2605*12016SGirish.Moodalbail@Sun.COM } else if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 2606*12016SGirish.Moodalbail@Sun.COM strrchr(ifap->ifa_name, ':') == NULL) { 2607*12016SGirish.Moodalbail@Sun.COM /* The interface was created using ipadm. */ 2608*12016SGirish.Moodalbail@Sun.COM pi->pi_autoconf = _B_FALSE; 2609*12016SGirish.Moodalbail@Sun.COM } 2610*12016SGirish.Moodalbail@Sun.COM } 2611*12016SGirish.Moodalbail@Sun.COM ipadm_free_addr_info(addrinfo); 2612*12016SGirish.Moodalbail@Sun.COM if (!pi->pi_autoconf) { 2613*12016SGirish.Moodalbail@Sun.COM pi->pi_token = in6addr_any; 2614*12016SGirish.Moodalbail@Sun.COM pi->pi_token_length = 0; 2615*12016SGirish.Moodalbail@Sun.COM } 2616*12016SGirish.Moodalbail@Sun.COM ipadm_close(iph); 2617*12016SGirish.Moodalbail@Sun.COM return (0); 2618*12016SGirish.Moodalbail@Sun.COM } 2619