16ba597c5SAnurag S. Maskey /*
26ba597c5SAnurag S. Maskey  * CDDL HEADER START
36ba597c5SAnurag S. Maskey  *
46ba597c5SAnurag S. Maskey  * The contents of this file are subject to the terms of the
56ba597c5SAnurag S. Maskey  * Common Development and Distribution License (the "License").
66ba597c5SAnurag S. Maskey  * You may not use this file except in compliance with the License.
76ba597c5SAnurag S. Maskey  *
86ba597c5SAnurag S. Maskey  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ba597c5SAnurag S. Maskey  * or http://www.opensolaris.org/os/licensing.
106ba597c5SAnurag S. Maskey  * See the License for the specific language governing permissions
116ba597c5SAnurag S. Maskey  * and limitations under the License.
126ba597c5SAnurag S. Maskey  *
136ba597c5SAnurag S. Maskey  * When distributing Covered Code, include this CDDL HEADER in each
146ba597c5SAnurag S. Maskey  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ba597c5SAnurag S. Maskey  * If applicable, add the following below this CDDL HEADER, with the
166ba597c5SAnurag S. Maskey  * fields enclosed by brackets "[]" replaced with your own identifying
176ba597c5SAnurag S. Maskey  * information: Portions Copyright [yyyy] [name of copyright owner]
186ba597c5SAnurag S. Maskey  *
196ba597c5SAnurag S. Maskey  * CDDL HEADER END
206ba597c5SAnurag S. Maskey  */
216ba597c5SAnurag S. Maskey 
226ba597c5SAnurag S. Maskey /*
23*f6da83d4SAnurag S. Maskey  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
246ba597c5SAnurag S. Maskey  */
256ba597c5SAnurag S. Maskey 
266ba597c5SAnurag S. Maskey #include <arpa/inet.h>
276ba597c5SAnurag S. Maskey #include <assert.h>
286ba597c5SAnurag S. Maskey #include <errno.h>
296ba597c5SAnurag S. Maskey #include <fcntl.h>
306ba597c5SAnurag S. Maskey #include <net/if.h>
316ba597c5SAnurag S. Maskey #include <net/route.h>
326ba597c5SAnurag S. Maskey #include <pthread.h>
336ba597c5SAnurag S. Maskey #include <stdio.h>
346ba597c5SAnurag S. Maskey #include <stdlib.h>
356ba597c5SAnurag S. Maskey #include <string.h>
366ba597c5SAnurag S. Maskey #include <strings.h>
376ba597c5SAnurag S. Maskey #include <sys/fcntl.h>
386ba597c5SAnurag S. Maskey #include <unistd.h>
396ba597c5SAnurag S. Maskey 
406ba597c5SAnurag S. Maskey #include <libnwam.h>
416ba597c5SAnurag S. Maskey #include "events.h"
426ba597c5SAnurag S. Maskey #include "ncp.h"
436ba597c5SAnurag S. Maskey #include "ncu.h"
446ba597c5SAnurag S. Maskey #include "util.h"
456ba597c5SAnurag S. Maskey 
466ba597c5SAnurag S. Maskey /*
476ba597c5SAnurag S. Maskey  * routing_events.c - this file contains routines to retrieve routing socket
486ba597c5SAnurag S. Maskey  * events and package them for high level processing.
496ba597c5SAnurag S. Maskey  */
506ba597c5SAnurag S. Maskey 
516ba597c5SAnurag S. Maskey #define	RTMBUFSZ	sizeof (struct rt_msghdr) + \
526ba597c5SAnurag S. Maskey 			(RTAX_MAX * sizeof (struct sockaddr_storage))
536ba597c5SAnurag S. Maskey 
546ba597c5SAnurag S. Maskey static void printaddrs(int, void *);
556ba597c5SAnurag S. Maskey static char *printaddr(void **);
566ba597c5SAnurag S. Maskey static void *getaddr(int, int, void *);
576ba597c5SAnurag S. Maskey static void setaddr(int, int *, void *, struct sockaddr *);
586ba597c5SAnurag S. Maskey 
596ba597c5SAnurag S. Maskey union rtm_buf
606ba597c5SAnurag S. Maskey {
616ba597c5SAnurag S. Maskey 	/* Routing information. */
626ba597c5SAnurag S. Maskey 	struct
636ba597c5SAnurag S. Maskey 	{
646ba597c5SAnurag S. Maskey 		struct rt_msghdr rtm;
656ba597c5SAnurag S. Maskey 		struct sockaddr_storage addr[RTAX_MAX];
666ba597c5SAnurag S. Maskey 	} r;
676ba597c5SAnurag S. Maskey 
686ba597c5SAnurag S. Maskey 	/* Interface information. */
696ba597c5SAnurag S. Maskey 	struct
706ba597c5SAnurag S. Maskey 	{
716ba597c5SAnurag S. Maskey 		struct if_msghdr ifm;
726ba597c5SAnurag S. Maskey 		struct sockaddr_storage addr[RTAX_MAX];
736ba597c5SAnurag S. Maskey 	} im;
746ba597c5SAnurag S. Maskey 
756ba597c5SAnurag S. Maskey 	/* Interface address information. */
766ba597c5SAnurag S. Maskey 	struct
776ba597c5SAnurag S. Maskey 	{
786ba597c5SAnurag S. Maskey 		struct ifa_msghdr ifa;
796ba597c5SAnurag S. Maskey 		struct sockaddr_storage addr[RTAX_MAX];
806ba597c5SAnurag S. Maskey 	} ia;
816ba597c5SAnurag S. Maskey };
826ba597c5SAnurag S. Maskey 
836ba597c5SAnurag S. Maskey static int v4_sock = -1;
846ba597c5SAnurag S. Maskey static int v6_sock = -1;
856ba597c5SAnurag S. Maskey static pthread_t v4_routing, v6_routing;
866ba597c5SAnurag S. Maskey static int seq = 0;
876ba597c5SAnurag S. Maskey 
886ba597c5SAnurag S. Maskey static const char *
rtmtype_str(int type)896ba597c5SAnurag S. Maskey rtmtype_str(int type)
906ba597c5SAnurag S. Maskey {
916ba597c5SAnurag S. Maskey 	static char typestr[12]; /* strlen("type ") + enough for an int */
926ba597c5SAnurag S. Maskey 
936ba597c5SAnurag S. Maskey 	switch (type) {
946ba597c5SAnurag S. Maskey 	case RTM_NEWADDR:
956ba597c5SAnurag S. Maskey 		return ("NEWADDR");
966ba597c5SAnurag S. Maskey 	case RTM_DELADDR:
976ba597c5SAnurag S. Maskey 		return ("DELADDR");
986ba597c5SAnurag S. Maskey 	case RTM_CHGADDR:
996ba597c5SAnurag S. Maskey 		return ("CHGADDR");
1006ba597c5SAnurag S. Maskey 	case RTM_FREEADDR:
1016ba597c5SAnurag S. Maskey 		return ("FREEADDR");
1026ba597c5SAnurag S. Maskey 	default:
1036ba597c5SAnurag S. Maskey 		(void) snprintf(typestr, sizeof (typestr), "type %d", type);
1046ba597c5SAnurag S. Maskey 		return (typestr);
1056ba597c5SAnurag S. Maskey 	}
1066ba597c5SAnurag S. Maskey }
1076ba597c5SAnurag S. Maskey 
1086ba597c5SAnurag S. Maskey /* ARGSUSED0 */
1096ba597c5SAnurag S. Maskey static void *
routing_events_v4(void * arg)1106ba597c5SAnurag S. Maskey routing_events_v4(void *arg)
1116ba597c5SAnurag S. Maskey {
1126ba597c5SAnurag S. Maskey 	int n;
1136ba597c5SAnurag S. Maskey 	union rtm_buf buffer;
1146ba597c5SAnurag S. Maskey 	struct rt_msghdr *rtm;
1156ba597c5SAnurag S. Maskey 	struct ifa_msghdr *ifa;
1166ba597c5SAnurag S. Maskey 	char *addrs, *if_name;
1176ba597c5SAnurag S. Maskey 	struct sockaddr_dl *addr_dl;
118*f6da83d4SAnurag S. Maskey 	struct sockaddr *addr, *netmask;
1196ba597c5SAnurag S. Maskey 	nwamd_event_t ip_event;
1206ba597c5SAnurag S. Maskey 
1216ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "v4 routing socket %d", v4_sock);
1226ba597c5SAnurag S. Maskey 
1236ba597c5SAnurag S. Maskey 	for (;;) {
1246ba597c5SAnurag S. Maskey 		rtm = &buffer.r.rtm;
1256ba597c5SAnurag S. Maskey 		n = read(v4_sock, &buffer, sizeof (buffer));
1266ba597c5SAnurag S. Maskey 		if (n == -1 && errno == EAGAIN) {
1276ba597c5SAnurag S. Maskey 			continue;
1286ba597c5SAnurag S. Maskey 		} else if (n == -1) {
1296ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "error reading routing socket "
1306ba597c5SAnurag S. Maskey 			    "%d: %m", v4_sock);
1316ba597c5SAnurag S. Maskey 			/* Low likelihood.  What's recovery path?  */
1326ba597c5SAnurag S. Maskey 			continue;
1336ba597c5SAnurag S. Maskey 		}
1346ba597c5SAnurag S. Maskey 
1356ba597c5SAnurag S. Maskey 		if (rtm->rtm_msglen < n) {
1366ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "only read %d bytes from "
1376ba597c5SAnurag S. Maskey 			    "routing socket but message claims to be "
1386ba597c5SAnurag S. Maskey 			    "of length %d", rtm->rtm_msglen);
1396ba597c5SAnurag S. Maskey 			continue;
1406ba597c5SAnurag S. Maskey 		}
1416ba597c5SAnurag S. Maskey 
1426ba597c5SAnurag S. Maskey 		if (rtm->rtm_version != RTM_VERSION) {
1436ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "tossing routing message of "
1446ba597c5SAnurag S. Maskey 			    "version %d type %d", rtm->rtm_version,
1456ba597c5SAnurag S. Maskey 			    rtm->rtm_type);
1466ba597c5SAnurag S. Maskey 			continue;
1476ba597c5SAnurag S. Maskey 		}
1486ba597c5SAnurag S. Maskey 
1496ba597c5SAnurag S. Maskey 		if (rtm->rtm_msglen != n) {
1506ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "routing message of %d size came from "
1516ba597c5SAnurag S. Maskey 			    "read of %d on socket %d", rtm->rtm_msglen,
1526ba597c5SAnurag S. Maskey 			    n, v4_sock);
1536ba597c5SAnurag S. Maskey 		}
1546ba597c5SAnurag S. Maskey 
1556ba597c5SAnurag S. Maskey 		switch (rtm->rtm_type) {
1566ba597c5SAnurag S. Maskey 		case RTM_NEWADDR:
1576ba597c5SAnurag S. Maskey 		case RTM_DELADDR:
1586ba597c5SAnurag S. Maskey 		case RTM_CHGADDR:
1596ba597c5SAnurag S. Maskey 		case RTM_FREEADDR:
1606ba597c5SAnurag S. Maskey 
1616ba597c5SAnurag S. Maskey 			ifa = (void *)rtm;
1626ba597c5SAnurag S. Maskey 			addrs = (char *)ifa + sizeof (*ifa);
1636ba597c5SAnurag S. Maskey 
1646ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "v4 routing message %s: "
1656ba597c5SAnurag S. Maskey 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
1666ba597c5SAnurag S. Maskey 			    ifa->ifam_index, ifa->ifam_flags);
1676ba597c5SAnurag S. Maskey 
1686ba597c5SAnurag S. Maskey 			if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
1696ba597c5SAnurag S. Maskey 			    ifa->ifam_addrs, addrs)) == NULL)
1706ba597c5SAnurag S. Maskey 				break;
1716ba597c5SAnurag S. Maskey 
1726ba597c5SAnurag S. Maskey 			/* Ignore routing socket messages for 0.0.0.0 */
1736ba597c5SAnurag S. Maskey 			/*LINTED*/
1746ba597c5SAnurag S. Maskey 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr
1756ba597c5SAnurag S. Maskey 			    == INADDR_ANY) {
1766ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "routing_events_v4: "
1776ba597c5SAnurag S. Maskey 				    "tossing message for 0.0.0.0");
1786ba597c5SAnurag S. Maskey 				break;
1796ba597c5SAnurag S. Maskey 			}
1806ba597c5SAnurag S. Maskey 
181*f6da83d4SAnurag S. Maskey 			if ((netmask = (struct sockaddr *)getaddr(RTA_NETMASK,
182*f6da83d4SAnurag S. Maskey 			    ifa->ifam_addrs, addrs)) == NULL)
183*f6da83d4SAnurag S. Maskey 				break;
184*f6da83d4SAnurag S. Maskey 
1856ba597c5SAnurag S. Maskey 			if ((addr_dl = (struct sockaddr_dl *)getaddr
1866ba597c5SAnurag S. Maskey 			    (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
1876ba597c5SAnurag S. Maskey 				break;
1886ba597c5SAnurag S. Maskey 			/*
1896ba597c5SAnurag S. Maskey 			 * We don't use the lladdr in this structure so we can
1906ba597c5SAnurag S. Maskey 			 * run over it.
1916ba597c5SAnurag S. Maskey 			 */
1926ba597c5SAnurag S. Maskey 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
1936ba597c5SAnurag S. Maskey 			if_name = addr_dl->sdl_data; /* no lifnum */
1946ba597c5SAnurag S. Maskey 
1956ba597c5SAnurag S. Maskey 			if (ifa->ifam_index == 0) {
1966ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "tossing index 0 message");
1976ba597c5SAnurag S. Maskey 				break;
1986ba597c5SAnurag S. Maskey 			}
1996ba597c5SAnurag S. Maskey 			if (ifa->ifam_type != rtm->rtm_type) {
2006ba597c5SAnurag S. Maskey 				nlog(LOG_INFO,
2016ba597c5SAnurag S. Maskey 				    "routing_events_v4: unhandled type %d",
2026ba597c5SAnurag S. Maskey 				    ifa->ifam_type);
2036ba597c5SAnurag S. Maskey 				break;
2046ba597c5SAnurag S. Maskey 			}
2056ba597c5SAnurag S. Maskey 
206*f6da83d4SAnurag S. Maskey 			printaddrs(ifa->ifam_addrs, addrs);
207*f6da83d4SAnurag S. Maskey 
2086ba597c5SAnurag S. Maskey 			/* Create and enqueue IF_STATE event */
2096ba597c5SAnurag S. Maskey 			ip_event = nwamd_event_init_if_state(if_name,
2106ba597c5SAnurag S. Maskey 			    ifa->ifam_flags,
2116ba597c5SAnurag S. Maskey 			    (rtm->rtm_type == RTM_NEWADDR ||
2126ba597c5SAnurag S. Maskey 			    rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
213*f6da83d4SAnurag S. Maskey 			    addr, netmask);
2146ba597c5SAnurag S. Maskey 			if (ip_event != NULL)
2156ba597c5SAnurag S. Maskey 				nwamd_event_enqueue(ip_event);
2166ba597c5SAnurag S. Maskey 			break;
2176ba597c5SAnurag S. Maskey 		}
2186ba597c5SAnurag S. Maskey 	}
2196ba597c5SAnurag S. Maskey 	/* NOTREACHED */
2206ba597c5SAnurag S. Maskey 	return (NULL);
2216ba597c5SAnurag S. Maskey }
2226ba597c5SAnurag S. Maskey 
2236ba597c5SAnurag S. Maskey /* ARGSUSED0 */
2246ba597c5SAnurag S. Maskey static void *
routing_events_v6(void * arg)2256ba597c5SAnurag S. Maskey routing_events_v6(void *arg)
2266ba597c5SAnurag S. Maskey {
2276ba597c5SAnurag S. Maskey 	int n;
2286ba597c5SAnurag S. Maskey 	union rtm_buf buffer;
2296ba597c5SAnurag S. Maskey 	struct rt_msghdr *rtm;
2306ba597c5SAnurag S. Maskey 	struct ifa_msghdr *ifa;
2316ba597c5SAnurag S. Maskey 	char *addrs, *if_name;
2326ba597c5SAnurag S. Maskey 	struct sockaddr_dl *addr_dl;
233*f6da83d4SAnurag S. Maskey 	struct sockaddr *addr, *netmask;
2346ba597c5SAnurag S. Maskey 	nwamd_event_t ip_event;
2356ba597c5SAnurag S. Maskey 
2366ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "v6 routing socket %d", v6_sock);
2376ba597c5SAnurag S. Maskey 
2386ba597c5SAnurag S. Maskey 	for (;;) {
2396ba597c5SAnurag S. Maskey 
2406ba597c5SAnurag S. Maskey 		rtm = &buffer.r.rtm;
2416ba597c5SAnurag S. Maskey 		n = read(v6_sock, &buffer, sizeof (buffer));
2426ba597c5SAnurag S. Maskey 		if (n == -1 && errno == EAGAIN) {
2436ba597c5SAnurag S. Maskey 			continue;
2446ba597c5SAnurag S. Maskey 		} else if (n == -1) {
2456ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "error reading routing socket "
2466ba597c5SAnurag S. Maskey 			    "%d: %m", v6_sock);
2476ba597c5SAnurag S. Maskey 			/* Low likelihood.  What's recovery path?  */
2486ba597c5SAnurag S. Maskey 			continue;
2496ba597c5SAnurag S. Maskey 		}
2506ba597c5SAnurag S. Maskey 
2516ba597c5SAnurag S. Maskey 		if (rtm->rtm_msglen < n) {
2526ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "only read %d bytes from "
2536ba597c5SAnurag S. Maskey 			    "routing socket but message claims to be "
2546ba597c5SAnurag S. Maskey 			    "of length %d", rtm->rtm_msglen);
2556ba597c5SAnurag S. Maskey 			continue;
2566ba597c5SAnurag S. Maskey 		}
2576ba597c5SAnurag S. Maskey 
2586ba597c5SAnurag S. Maskey 		if (rtm->rtm_version != RTM_VERSION) {
2596ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "tossing routing message of "
2606ba597c5SAnurag S. Maskey 			    "version %d type %d", rtm->rtm_version,
2616ba597c5SAnurag S. Maskey 			    rtm->rtm_type);
2626ba597c5SAnurag S. Maskey 			continue;
2636ba597c5SAnurag S. Maskey 		}
2646ba597c5SAnurag S. Maskey 
2656ba597c5SAnurag S. Maskey 		if (rtm->rtm_msglen != n) {
2666ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "routing message of %d size came from "
2676ba597c5SAnurag S. Maskey 			    "read of %d on socket %d", rtm->rtm_msglen,
2686ba597c5SAnurag S. Maskey 			    n, v6_sock);
2696ba597c5SAnurag S. Maskey 		}
2706ba597c5SAnurag S. Maskey 
2716ba597c5SAnurag S. Maskey 		switch (rtm->rtm_type) {
2726ba597c5SAnurag S. Maskey 		case RTM_NEWADDR:
2736ba597c5SAnurag S. Maskey 		case RTM_DELADDR:
2746ba597c5SAnurag S. Maskey 		case RTM_CHGADDR:
2756ba597c5SAnurag S. Maskey 		case RTM_FREEADDR:
2766ba597c5SAnurag S. Maskey 
2776ba597c5SAnurag S. Maskey 			ifa = (void *)rtm;
2786ba597c5SAnurag S. Maskey 			addrs = (char *)ifa + sizeof (*ifa);
2796ba597c5SAnurag S. Maskey 
2806ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "v6 routing message %s: "
2816ba597c5SAnurag S. Maskey 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
2826ba597c5SAnurag S. Maskey 			    ifa->ifam_index, ifa->ifam_flags);
2836ba597c5SAnurag S. Maskey 
2846ba597c5SAnurag S. Maskey 			if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
2856ba597c5SAnurag S. Maskey 			    ifa->ifam_addrs, addrs)) == NULL)
2866ba597c5SAnurag S. Maskey 				break;
2876ba597c5SAnurag S. Maskey 
288*f6da83d4SAnurag S. Maskey 			/* Ignore routing socket messages for :: & linklocal */
289*f6da83d4SAnurag S. Maskey 			/*LINTED*/
290*f6da83d4SAnurag S. Maskey 			if (IN6_IS_ADDR_UNSPECIFIED(
291*f6da83d4SAnurag S. Maskey 			    &((struct sockaddr_in6 *)addr)->sin6_addr)) {
292*f6da83d4SAnurag S. Maskey 				nlog(LOG_INFO, "routing_events_v6: "
293*f6da83d4SAnurag S. Maskey 				    "tossing message for ::");
294*f6da83d4SAnurag S. Maskey 				break;
295*f6da83d4SAnurag S. Maskey 			}
2966ba597c5SAnurag S. Maskey 			/*LINTED*/
2976ba597c5SAnurag S. Maskey 			if (IN6_IS_ADDR_LINKLOCAL(
2986ba597c5SAnurag S. Maskey 			    &((struct sockaddr_in6 *)addr)->sin6_addr)) {
2996ba597c5SAnurag S. Maskey 				nlog(LOG_INFO, "routing_events_v6: "
3006ba597c5SAnurag S. Maskey 				    "tossing message for link local address");
3016ba597c5SAnurag S. Maskey 				break;
3026ba597c5SAnurag S. Maskey 			}
3036ba597c5SAnurag S. Maskey 
304*f6da83d4SAnurag S. Maskey 			if ((netmask =
305*f6da83d4SAnurag S. Maskey 			    (struct sockaddr *)getaddr(RTA_NETMASK,
306*f6da83d4SAnurag S. Maskey 			    ifa->ifam_addrs, addrs)) == NULL)
307*f6da83d4SAnurag S. Maskey 				break;
308*f6da83d4SAnurag S. Maskey 
3096ba597c5SAnurag S. Maskey 			if ((addr_dl = (struct sockaddr_dl *)getaddr
3106ba597c5SAnurag S. Maskey 			    (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
3116ba597c5SAnurag S. Maskey 				break;
3126ba597c5SAnurag S. Maskey 			/*
3136ba597c5SAnurag S. Maskey 			 * We don't use the lladdr in this structure so we can
3146ba597c5SAnurag S. Maskey 			 * run over it.
3156ba597c5SAnurag S. Maskey 			 */
3166ba597c5SAnurag S. Maskey 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
3176ba597c5SAnurag S. Maskey 			if_name = addr_dl->sdl_data; /* no lifnum */
3186ba597c5SAnurag S. Maskey 
3196ba597c5SAnurag S. Maskey 			if (ifa->ifam_index == 0) {
3206ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG, "tossing index 0 message");
3216ba597c5SAnurag S. Maskey 				break;
3226ba597c5SAnurag S. Maskey 			}
3236ba597c5SAnurag S. Maskey 			if (ifa->ifam_type != rtm->rtm_type) {
3246ba597c5SAnurag S. Maskey 				nlog(LOG_DEBUG,
3256ba597c5SAnurag S. Maskey 				    "routing_events_v6: unhandled type %d",
3266ba597c5SAnurag S. Maskey 				    ifa->ifam_type);
3276ba597c5SAnurag S. Maskey 				break;
3286ba597c5SAnurag S. Maskey 			}
3296ba597c5SAnurag S. Maskey 
330*f6da83d4SAnurag S. Maskey 			printaddrs(ifa->ifam_addrs, addrs);
331*f6da83d4SAnurag S. Maskey 
3326ba597c5SAnurag S. Maskey 			/* Create and enqueue IF_STATE event */
3336ba597c5SAnurag S. Maskey 			ip_event = nwamd_event_init_if_state(if_name,
3346ba597c5SAnurag S. Maskey 			    ifa->ifam_flags,
3356ba597c5SAnurag S. Maskey 			    (rtm->rtm_type == RTM_NEWADDR ||
3366ba597c5SAnurag S. Maskey 			    rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
337*f6da83d4SAnurag S. Maskey 			    addr, netmask);
3386ba597c5SAnurag S. Maskey 			if (ip_event != NULL)
3396ba597c5SAnurag S. Maskey 				nwamd_event_enqueue(ip_event);
3406ba597c5SAnurag S. Maskey 			break;
3416ba597c5SAnurag S. Maskey 
3426ba597c5SAnurag S. Maskey 		}
3436ba597c5SAnurag S. Maskey 	}
3446ba597c5SAnurag S. Maskey 	/* NOTREACHED */
3456ba597c5SAnurag S. Maskey 	return (NULL);
3466ba597c5SAnurag S. Maskey }
3476ba597c5SAnurag S. Maskey 
3486ba597c5SAnurag S. Maskey void
nwamd_routing_events_init(void)3496ba597c5SAnurag S. Maskey nwamd_routing_events_init(void)
3506ba597c5SAnurag S. Maskey {
3516ba597c5SAnurag S. Maskey 	pthread_attr_t attr;
3526ba597c5SAnurag S. Maskey 
3536ba597c5SAnurag S. Maskey 	/*
3546ba597c5SAnurag S. Maskey 	 * Initialize routing sockets here so that we know the routing threads
3556ba597c5SAnurag S. Maskey 	 * (and any requests to add a route) will be working with a valid socket
3566ba597c5SAnurag S. Maskey 	 * by the time we start handling events.
3576ba597c5SAnurag S. Maskey 	 */
3586ba597c5SAnurag S. Maskey 	v4_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET);
3596ba597c5SAnurag S. Maskey 	if (v4_sock == -1)
3606ba597c5SAnurag S. Maskey 		pfail("failed to open v4 routing socket: %m");
3616ba597c5SAnurag S. Maskey 
3626ba597c5SAnurag S. Maskey 	v6_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET6);
3636ba597c5SAnurag S. Maskey 	if (v6_sock == -1)
3646ba597c5SAnurag S. Maskey 		pfail("failed to open v6 routing socket: %m");
3656ba597c5SAnurag S. Maskey 
3666ba597c5SAnurag S. Maskey 	(void) pthread_attr_init(&attr);
3676ba597c5SAnurag S. Maskey 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3686ba597c5SAnurag S. Maskey 	if (pthread_create(&v4_routing, &attr, routing_events_v4, NULL) != 0 ||
3696ba597c5SAnurag S. Maskey 	    pthread_create(&v6_routing, &attr, routing_events_v6, NULL) != 0)
3706ba597c5SAnurag S. Maskey 		pfail("routing thread creation failed");
3716ba597c5SAnurag S. Maskey 	(void) pthread_attr_destroy(&attr);
3726ba597c5SAnurag S. Maskey }
3736ba597c5SAnurag S. Maskey 
3746ba597c5SAnurag S. Maskey void
nwamd_routing_events_fini(void)3756ba597c5SAnurag S. Maskey nwamd_routing_events_fini(void)
3766ba597c5SAnurag S. Maskey {
3776ba597c5SAnurag S. Maskey 	(void) pthread_cancel(v4_routing);
3786ba597c5SAnurag S. Maskey 	(void) pthread_cancel(v6_routing);
3796ba597c5SAnurag S. Maskey }
3806ba597c5SAnurag S. Maskey 
3816ba597c5SAnurag S. Maskey void
nwamd_add_route(struct sockaddr * dest,struct sockaddr * mask,struct sockaddr * gateway,const char * ifname)3826ba597c5SAnurag S. Maskey nwamd_add_route(struct sockaddr *dest, struct sockaddr *mask,
3836ba597c5SAnurag S. Maskey     struct sockaddr *gateway, const char *ifname)
3846ba597c5SAnurag S. Maskey {
3856ba597c5SAnurag S. Maskey 	char rtbuf[RTMBUFSZ];
3866ba597c5SAnurag S. Maskey 	/* LINTED E_BAD_PTR_CAST_ALIGN */
3876ba597c5SAnurag S. Maskey 	struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
3886ba597c5SAnurag S. Maskey 	void *addrs = rtbuf + sizeof (struct rt_msghdr);
3896ba597c5SAnurag S. Maskey 	struct sockaddr_dl sdl;
3906ba597c5SAnurag S. Maskey 	int rlen, index;
3916ba597c5SAnurag S. Maskey 	int af;
3926ba597c5SAnurag S. Maskey 
3936ba597c5SAnurag S. Maskey 	af = gateway->sa_family;
3946ba597c5SAnurag S. Maskey 
395*f6da83d4SAnurag S. Maskey 	/* retrieve the index value for the interface */
396*f6da83d4SAnurag S. Maskey 	if ((index = if_nametoindex(ifname)) == 0) {
397*f6da83d4SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_add_route: if_nametoindex failed on %s",
398*f6da83d4SAnurag S. Maskey 		    ifname);
3996ba597c5SAnurag S. Maskey 		return;
4006ba597c5SAnurag S. Maskey 	}
401*f6da83d4SAnurag S. Maskey 
4026ba597c5SAnurag S. Maskey 	(void) bzero(&sdl, sizeof (struct sockaddr_dl));
4036ba597c5SAnurag S. Maskey 	sdl.sdl_family = AF_LINK;
4046ba597c5SAnurag S. Maskey 	sdl.sdl_index = index;
4056ba597c5SAnurag S. Maskey 
4066ba597c5SAnurag S. Maskey 	(void) bzero(rtm, RTMBUFSZ);
4076ba597c5SAnurag S. Maskey 	rtm->rtm_pid = getpid();
4086ba597c5SAnurag S. Maskey 	rtm->rtm_type = RTM_ADD;
4096ba597c5SAnurag S. Maskey 	rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
4106ba597c5SAnurag S. Maskey 	rtm->rtm_version = RTM_VERSION;
4116ba597c5SAnurag S. Maskey 	rtm->rtm_seq = ++seq;
4126ba597c5SAnurag S. Maskey 	rtm->rtm_msglen = sizeof (rtbuf);
4136ba597c5SAnurag S. Maskey 	setaddr(RTA_DST, &rtm->rtm_addrs, &addrs, dest);
4146ba597c5SAnurag S. Maskey 	setaddr(RTA_GATEWAY, &rtm->rtm_addrs, &addrs, gateway);
4156ba597c5SAnurag S. Maskey 	setaddr(RTA_NETMASK, &rtm->rtm_addrs, &addrs, mask);
4166ba597c5SAnurag S. Maskey 	setaddr(RTA_IFP, &rtm->rtm_addrs, &addrs, (struct sockaddr *)&sdl);
4176ba597c5SAnurag S. Maskey 
4186ba597c5SAnurag S. Maskey 	if ((rlen = write(af == AF_INET ? v4_sock : v6_sock,
4196ba597c5SAnurag S. Maskey 	    rtbuf, rtm->rtm_msglen)) < 0) {
4206ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_add_route: "
4216ba597c5SAnurag S. Maskey 		    "got error %s writing to routing socket", strerror(errno));
4226ba597c5SAnurag S. Maskey 	} else if (rlen < rtm->rtm_msglen) {
4236ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_add_route: "
4246ba597c5SAnurag S. Maskey 		    "only wrote %d bytes of %d to routing socket\n",
4256ba597c5SAnurag S. Maskey 		    rlen, rtm->rtm_msglen);
4266ba597c5SAnurag S. Maskey 	}
4276ba597c5SAnurag S. Maskey }
4286ba597c5SAnurag S. Maskey 
4296ba597c5SAnurag S. Maskey static char *
printaddr(void ** address)4306ba597c5SAnurag S. Maskey printaddr(void **address)
4316ba597c5SAnurag S. Maskey {
4326ba597c5SAnurag S. Maskey 	static char buffer[80];
4336ba597c5SAnurag S. Maskey 	sa_family_t family = *(sa_family_t *)*address;
4346ba597c5SAnurag S. Maskey 	struct sockaddr_in *s4 = *address;
4356ba597c5SAnurag S. Maskey 	struct sockaddr_in6 *s6 = *address;
4366ba597c5SAnurag S. Maskey 	struct sockaddr_dl *dl = *address;
4376ba597c5SAnurag S. Maskey 
4386ba597c5SAnurag S. Maskey 	switch (family) {
4396ba597c5SAnurag S. Maskey 	case AF_UNSPEC:
4406ba597c5SAnurag S. Maskey 		(void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer,
4416ba597c5SAnurag S. Maskey 		    sizeof (buffer));
4426ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (*s4);
4436ba597c5SAnurag S. Maskey 		break;
4446ba597c5SAnurag S. Maskey 	case AF_INET:
4456ba597c5SAnurag S. Maskey 		(void) inet_ntop(AF_INET, &s4->sin_addr, buffer,
4466ba597c5SAnurag S. Maskey 		    sizeof (buffer));
4476ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (*s4);
4486ba597c5SAnurag S. Maskey 		break;
4496ba597c5SAnurag S. Maskey 	case AF_INET6:
4506ba597c5SAnurag S. Maskey 		(void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer,
4516ba597c5SAnurag S. Maskey 		    sizeof (buffer));
4526ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (*s6);
4536ba597c5SAnurag S. Maskey 		break;
4546ba597c5SAnurag S. Maskey 	case AF_LINK:
4556ba597c5SAnurag S. Maskey 		(void) snprintf(buffer, sizeof (buffer), "link %.*s",
4566ba597c5SAnurag S. Maskey 		    dl->sdl_nlen, dl->sdl_data);
4576ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (*dl);
4586ba597c5SAnurag S. Maskey 		break;
4596ba597c5SAnurag S. Maskey 	default:
4606ba597c5SAnurag S. Maskey 		/*
4616ba597c5SAnurag S. Maskey 		 * We can't reliably update the size of this thing
4626ba597c5SAnurag S. Maskey 		 * because we don't know what its type is.  So bump
4636ba597c5SAnurag S. Maskey 		 * it by a sockaddr_in and see what happens.  The
4646ba597c5SAnurag S. Maskey 		 * caller should really make sure this never happens.
4656ba597c5SAnurag S. Maskey 		 */
4666ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (*s4);
4676ba597c5SAnurag S. Maskey 		(void) snprintf(buffer, sizeof (buffer),
4686ba597c5SAnurag S. Maskey 		    "unknown address family %d", family);
4696ba597c5SAnurag S. Maskey 		break;
4706ba597c5SAnurag S. Maskey 	}
4716ba597c5SAnurag S. Maskey 	return (buffer);
4726ba597c5SAnurag S. Maskey }
4736ba597c5SAnurag S. Maskey 
4746ba597c5SAnurag S. Maskey static void
printaddrs(int mask,void * address)4756ba597c5SAnurag S. Maskey printaddrs(int mask, void *address)
4766ba597c5SAnurag S. Maskey {
4776ba597c5SAnurag S. Maskey 	if (mask == 0)
4786ba597c5SAnurag S. Maskey 		return;
4796ba597c5SAnurag S. Maskey 	if (mask & RTA_DST)
4806ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "destination address: %s", printaddr(&address));
4816ba597c5SAnurag S. Maskey 	if (mask & RTA_GATEWAY)
4826ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "gateway address: %s", printaddr(&address));
4836ba597c5SAnurag S. Maskey 	if (mask & RTA_NETMASK)
4846ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "netmask: %s", printaddr(&address));
4856ba597c5SAnurag S. Maskey 	if (mask & RTA_GENMASK)
4866ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "cloning mask: %s", printaddr(&address));
4876ba597c5SAnurag S. Maskey 	if (mask & RTA_IFP)
4886ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "interface name: %s", printaddr(&address));
4896ba597c5SAnurag S. Maskey 	if (mask & RTA_IFA)
4906ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "interface address: %s", printaddr(&address));
4916ba597c5SAnurag S. Maskey 	if (mask & RTA_AUTHOR)
4926ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "author: %s", printaddr(&address));
4936ba597c5SAnurag S. Maskey 	if (mask & RTA_BRD)
4946ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "broadcast address: %s", printaddr(&address));
4956ba597c5SAnurag S. Maskey }
4966ba597c5SAnurag S. Maskey 
4976ba597c5SAnurag S. Maskey static void
nextaddr(void ** address)4986ba597c5SAnurag S. Maskey nextaddr(void **address)
4996ba597c5SAnurag S. Maskey {
5006ba597c5SAnurag S. Maskey 	sa_family_t family = *(sa_family_t *)*address;
5016ba597c5SAnurag S. Maskey 
5026ba597c5SAnurag S. Maskey 	switch (family) {
5036ba597c5SAnurag S. Maskey 	case AF_UNSPEC:
5046ba597c5SAnurag S. Maskey 	case AF_INET:
5056ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (struct sockaddr_in);
5066ba597c5SAnurag S. Maskey 		break;
5076ba597c5SAnurag S. Maskey 	case AF_INET6:
5086ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (struct sockaddr_in6);
5096ba597c5SAnurag S. Maskey 		break;
5106ba597c5SAnurag S. Maskey 	case AF_LINK:
5116ba597c5SAnurag S. Maskey 		*address = (char *)*address + sizeof (struct sockaddr_dl);
5126ba597c5SAnurag S. Maskey 		break;
5136ba597c5SAnurag S. Maskey 	default:
5146ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "unknown af (%d) while parsing rtm", family);
5156ba597c5SAnurag S. Maskey 		break;
5166ba597c5SAnurag S. Maskey 	}
5176ba597c5SAnurag S. Maskey }
5186ba597c5SAnurag S. Maskey 
5196ba597c5SAnurag S. Maskey static void *
getaddr(int addrid,int mask,void * addresses)5206ba597c5SAnurag S. Maskey getaddr(int addrid, int mask, void *addresses)
5216ba597c5SAnurag S. Maskey {
5226ba597c5SAnurag S. Maskey 	int i;
5236ba597c5SAnurag S. Maskey 	void *p = addresses;
5246ba597c5SAnurag S. Maskey 
5256ba597c5SAnurag S. Maskey 	if ((mask & addrid) == 0)
5266ba597c5SAnurag S. Maskey 		return (NULL);
5276ba597c5SAnurag S. Maskey 
5286ba597c5SAnurag S. Maskey 	for (i = 1; i < addrid; i <<= 1) {
5296ba597c5SAnurag S. Maskey 		if (i & mask)
5306ba597c5SAnurag S. Maskey 			nextaddr(&p);
5316ba597c5SAnurag S. Maskey 	}
5326ba597c5SAnurag S. Maskey 	return (p);
5336ba597c5SAnurag S. Maskey }
5346ba597c5SAnurag S. Maskey 
5356ba597c5SAnurag S. Maskey static void
setaddr(int addrid,int * maskp,void * addressesp,struct sockaddr * address)5366ba597c5SAnurag S. Maskey setaddr(int addrid, int *maskp, void *addressesp, struct sockaddr *address)
5376ba597c5SAnurag S. Maskey {
5386ba597c5SAnurag S. Maskey 	struct sockaddr *p = *((struct sockaddr **)addressesp);
5396ba597c5SAnurag S. Maskey 
5406ba597c5SAnurag S. Maskey 	*maskp |= addrid;
5416ba597c5SAnurag S. Maskey 
5426ba597c5SAnurag S. Maskey 	switch (address->sa_family) {
5436ba597c5SAnurag S. Maskey 	case AF_INET:
5446ba597c5SAnurag S. Maskey 		(void) memcpy(p, address, sizeof (struct sockaddr_in));
5456ba597c5SAnurag S. Maskey 		break;
5466ba597c5SAnurag S. Maskey 	case AF_INET6:
5476ba597c5SAnurag S. Maskey 		(void) memcpy(p, address, sizeof (struct sockaddr_in6));
5486ba597c5SAnurag S. Maskey 		break;
5496ba597c5SAnurag S. Maskey 	case AF_LINK:
5506ba597c5SAnurag S. Maskey 		(void) memcpy(p, address, sizeof (struct sockaddr_dl));
5516ba597c5SAnurag S. Maskey 		break;
5526ba597c5SAnurag S. Maskey 	default:
5536ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "setaddr: unknown af (%d) while setting addr",
5546ba597c5SAnurag S. Maskey 		    address->sa_family);
5556ba597c5SAnurag S. Maskey 		break;
5566ba597c5SAnurag S. Maskey 	}
5576ba597c5SAnurag S. Maskey 	nextaddr(addressesp);
5586ba597c5SAnurag S. Maskey }
559