xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/nwamd/routing_events.c (revision 12576:ab8aacaead3f)
111767SAnurag.Maskey@Sun.COM /*
211767SAnurag.Maskey@Sun.COM  * CDDL HEADER START
311767SAnurag.Maskey@Sun.COM  *
411767SAnurag.Maskey@Sun.COM  * The contents of this file are subject to the terms of the
511767SAnurag.Maskey@Sun.COM  * Common Development and Distribution License (the "License").
611767SAnurag.Maskey@Sun.COM  * You may not use this file except in compliance with the License.
711767SAnurag.Maskey@Sun.COM  *
811767SAnurag.Maskey@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911767SAnurag.Maskey@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011767SAnurag.Maskey@Sun.COM  * See the License for the specific language governing permissions
1111767SAnurag.Maskey@Sun.COM  * and limitations under the License.
1211767SAnurag.Maskey@Sun.COM  *
1311767SAnurag.Maskey@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411767SAnurag.Maskey@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511767SAnurag.Maskey@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611767SAnurag.Maskey@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711767SAnurag.Maskey@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811767SAnurag.Maskey@Sun.COM  *
1911767SAnurag.Maskey@Sun.COM  * CDDL HEADER END
2011767SAnurag.Maskey@Sun.COM  */
2111767SAnurag.Maskey@Sun.COM 
2211767SAnurag.Maskey@Sun.COM /*
23*12576SAnurag.Maskey@Oracle.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411767SAnurag.Maskey@Sun.COM  */
2511767SAnurag.Maskey@Sun.COM 
2611767SAnurag.Maskey@Sun.COM #include <arpa/inet.h>
2711767SAnurag.Maskey@Sun.COM #include <assert.h>
2811767SAnurag.Maskey@Sun.COM #include <errno.h>
2911767SAnurag.Maskey@Sun.COM #include <fcntl.h>
3011767SAnurag.Maskey@Sun.COM #include <net/if.h>
3111767SAnurag.Maskey@Sun.COM #include <net/route.h>
3211767SAnurag.Maskey@Sun.COM #include <pthread.h>
3311767SAnurag.Maskey@Sun.COM #include <stdio.h>
3411767SAnurag.Maskey@Sun.COM #include <stdlib.h>
3511767SAnurag.Maskey@Sun.COM #include <string.h>
3611767SAnurag.Maskey@Sun.COM #include <strings.h>
3711767SAnurag.Maskey@Sun.COM #include <sys/fcntl.h>
3811767SAnurag.Maskey@Sun.COM #include <unistd.h>
3911767SAnurag.Maskey@Sun.COM 
4011767SAnurag.Maskey@Sun.COM #include <libnwam.h>
4111767SAnurag.Maskey@Sun.COM #include "events.h"
4211767SAnurag.Maskey@Sun.COM #include "ncp.h"
4311767SAnurag.Maskey@Sun.COM #include "ncu.h"
4411767SAnurag.Maskey@Sun.COM #include "util.h"
4511767SAnurag.Maskey@Sun.COM 
4611767SAnurag.Maskey@Sun.COM /*
4711767SAnurag.Maskey@Sun.COM  * routing_events.c - this file contains routines to retrieve routing socket
4811767SAnurag.Maskey@Sun.COM  * events and package them for high level processing.
4911767SAnurag.Maskey@Sun.COM  */
5011767SAnurag.Maskey@Sun.COM 
5111767SAnurag.Maskey@Sun.COM #define	RTMBUFSZ	sizeof (struct rt_msghdr) + \
5211767SAnurag.Maskey@Sun.COM 			(RTAX_MAX * sizeof (struct sockaddr_storage))
5311767SAnurag.Maskey@Sun.COM 
5411767SAnurag.Maskey@Sun.COM static void printaddrs(int, void *);
5511767SAnurag.Maskey@Sun.COM static char *printaddr(void **);
5611767SAnurag.Maskey@Sun.COM static void *getaddr(int, int, void *);
5711767SAnurag.Maskey@Sun.COM static void setaddr(int, int *, void *, struct sockaddr *);
5811767SAnurag.Maskey@Sun.COM 
5911767SAnurag.Maskey@Sun.COM union rtm_buf
6011767SAnurag.Maskey@Sun.COM {
6111767SAnurag.Maskey@Sun.COM 	/* Routing information. */
6211767SAnurag.Maskey@Sun.COM 	struct
6311767SAnurag.Maskey@Sun.COM 	{
6411767SAnurag.Maskey@Sun.COM 		struct rt_msghdr rtm;
6511767SAnurag.Maskey@Sun.COM 		struct sockaddr_storage addr[RTAX_MAX];
6611767SAnurag.Maskey@Sun.COM 	} r;
6711767SAnurag.Maskey@Sun.COM 
6811767SAnurag.Maskey@Sun.COM 	/* Interface information. */
6911767SAnurag.Maskey@Sun.COM 	struct
7011767SAnurag.Maskey@Sun.COM 	{
7111767SAnurag.Maskey@Sun.COM 		struct if_msghdr ifm;
7211767SAnurag.Maskey@Sun.COM 		struct sockaddr_storage addr[RTAX_MAX];
7311767SAnurag.Maskey@Sun.COM 	} im;
7411767SAnurag.Maskey@Sun.COM 
7511767SAnurag.Maskey@Sun.COM 	/* Interface address information. */
7611767SAnurag.Maskey@Sun.COM 	struct
7711767SAnurag.Maskey@Sun.COM 	{
7811767SAnurag.Maskey@Sun.COM 		struct ifa_msghdr ifa;
7911767SAnurag.Maskey@Sun.COM 		struct sockaddr_storage addr[RTAX_MAX];
8011767SAnurag.Maskey@Sun.COM 	} ia;
8111767SAnurag.Maskey@Sun.COM };
8211767SAnurag.Maskey@Sun.COM 
8311767SAnurag.Maskey@Sun.COM static int v4_sock = -1;
8411767SAnurag.Maskey@Sun.COM static int v6_sock = -1;
8511767SAnurag.Maskey@Sun.COM static pthread_t v4_routing, v6_routing;
8611767SAnurag.Maskey@Sun.COM static int seq = 0;
8711767SAnurag.Maskey@Sun.COM 
8811767SAnurag.Maskey@Sun.COM static const char *
rtmtype_str(int type)8911767SAnurag.Maskey@Sun.COM rtmtype_str(int type)
9011767SAnurag.Maskey@Sun.COM {
9111767SAnurag.Maskey@Sun.COM 	static char typestr[12]; /* strlen("type ") + enough for an int */
9211767SAnurag.Maskey@Sun.COM 
9311767SAnurag.Maskey@Sun.COM 	switch (type) {
9411767SAnurag.Maskey@Sun.COM 	case RTM_NEWADDR:
9511767SAnurag.Maskey@Sun.COM 		return ("NEWADDR");
9611767SAnurag.Maskey@Sun.COM 	case RTM_DELADDR:
9711767SAnurag.Maskey@Sun.COM 		return ("DELADDR");
9811767SAnurag.Maskey@Sun.COM 	case RTM_CHGADDR:
9911767SAnurag.Maskey@Sun.COM 		return ("CHGADDR");
10011767SAnurag.Maskey@Sun.COM 	case RTM_FREEADDR:
10111767SAnurag.Maskey@Sun.COM 		return ("FREEADDR");
10211767SAnurag.Maskey@Sun.COM 	default:
10311767SAnurag.Maskey@Sun.COM 		(void) snprintf(typestr, sizeof (typestr), "type %d", type);
10411767SAnurag.Maskey@Sun.COM 		return (typestr);
10511767SAnurag.Maskey@Sun.COM 	}
10611767SAnurag.Maskey@Sun.COM }
10711767SAnurag.Maskey@Sun.COM 
10811767SAnurag.Maskey@Sun.COM /* ARGSUSED0 */
10911767SAnurag.Maskey@Sun.COM static void *
routing_events_v4(void * arg)11011767SAnurag.Maskey@Sun.COM routing_events_v4(void *arg)
11111767SAnurag.Maskey@Sun.COM {
11211767SAnurag.Maskey@Sun.COM 	int n;
11311767SAnurag.Maskey@Sun.COM 	union rtm_buf buffer;
11411767SAnurag.Maskey@Sun.COM 	struct rt_msghdr *rtm;
11511767SAnurag.Maskey@Sun.COM 	struct ifa_msghdr *ifa;
11611767SAnurag.Maskey@Sun.COM 	char *addrs, *if_name;
11711767SAnurag.Maskey@Sun.COM 	struct sockaddr_dl *addr_dl;
118*12576SAnurag.Maskey@Oracle.COM 	struct sockaddr *addr, *netmask;
11911767SAnurag.Maskey@Sun.COM 	nwamd_event_t ip_event;
12011767SAnurag.Maskey@Sun.COM 
12111767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "v4 routing socket %d", v4_sock);
12211767SAnurag.Maskey@Sun.COM 
12311767SAnurag.Maskey@Sun.COM 	for (;;) {
12411767SAnurag.Maskey@Sun.COM 		rtm = &buffer.r.rtm;
12511767SAnurag.Maskey@Sun.COM 		n = read(v4_sock, &buffer, sizeof (buffer));
12611767SAnurag.Maskey@Sun.COM 		if (n == -1 && errno == EAGAIN) {
12711767SAnurag.Maskey@Sun.COM 			continue;
12811767SAnurag.Maskey@Sun.COM 		} else if (n == -1) {
12911767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "error reading routing socket "
13011767SAnurag.Maskey@Sun.COM 			    "%d: %m", v4_sock);
13111767SAnurag.Maskey@Sun.COM 			/* Low likelihood.  What's recovery path?  */
13211767SAnurag.Maskey@Sun.COM 			continue;
13311767SAnurag.Maskey@Sun.COM 		}
13411767SAnurag.Maskey@Sun.COM 
13511767SAnurag.Maskey@Sun.COM 		if (rtm->rtm_msglen < n) {
13611767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "only read %d bytes from "
13711767SAnurag.Maskey@Sun.COM 			    "routing socket but message claims to be "
13811767SAnurag.Maskey@Sun.COM 			    "of length %d", rtm->rtm_msglen);
13911767SAnurag.Maskey@Sun.COM 			continue;
14011767SAnurag.Maskey@Sun.COM 		}
14111767SAnurag.Maskey@Sun.COM 
14211767SAnurag.Maskey@Sun.COM 		if (rtm->rtm_version != RTM_VERSION) {
14311767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "tossing routing message of "
14411767SAnurag.Maskey@Sun.COM 			    "version %d type %d", rtm->rtm_version,
14511767SAnurag.Maskey@Sun.COM 			    rtm->rtm_type);
14611767SAnurag.Maskey@Sun.COM 			continue;
14711767SAnurag.Maskey@Sun.COM 		}
14811767SAnurag.Maskey@Sun.COM 
14911767SAnurag.Maskey@Sun.COM 		if (rtm->rtm_msglen != n) {
15011767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "routing message of %d size came from "
15111767SAnurag.Maskey@Sun.COM 			    "read of %d on socket %d", rtm->rtm_msglen,
15211767SAnurag.Maskey@Sun.COM 			    n, v4_sock);
15311767SAnurag.Maskey@Sun.COM 		}
15411767SAnurag.Maskey@Sun.COM 
15511767SAnurag.Maskey@Sun.COM 		switch (rtm->rtm_type) {
15611767SAnurag.Maskey@Sun.COM 		case RTM_NEWADDR:
15711767SAnurag.Maskey@Sun.COM 		case RTM_DELADDR:
15811767SAnurag.Maskey@Sun.COM 		case RTM_CHGADDR:
15911767SAnurag.Maskey@Sun.COM 		case RTM_FREEADDR:
16011767SAnurag.Maskey@Sun.COM 
16111767SAnurag.Maskey@Sun.COM 			ifa = (void *)rtm;
16211767SAnurag.Maskey@Sun.COM 			addrs = (char *)ifa + sizeof (*ifa);
16311767SAnurag.Maskey@Sun.COM 
16411767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "v4 routing message %s: "
16511767SAnurag.Maskey@Sun.COM 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
16611767SAnurag.Maskey@Sun.COM 			    ifa->ifam_index, ifa->ifam_flags);
16711767SAnurag.Maskey@Sun.COM 
16811767SAnurag.Maskey@Sun.COM 			if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
16911767SAnurag.Maskey@Sun.COM 			    ifa->ifam_addrs, addrs)) == NULL)
17011767SAnurag.Maskey@Sun.COM 				break;
17111767SAnurag.Maskey@Sun.COM 
17211767SAnurag.Maskey@Sun.COM 			/* Ignore routing socket messages for 0.0.0.0 */
17311767SAnurag.Maskey@Sun.COM 			/*LINTED*/
17411767SAnurag.Maskey@Sun.COM 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr
17511767SAnurag.Maskey@Sun.COM 			    == INADDR_ANY) {
17611767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "routing_events_v4: "
17711767SAnurag.Maskey@Sun.COM 				    "tossing message for 0.0.0.0");
17811767SAnurag.Maskey@Sun.COM 				break;
17911767SAnurag.Maskey@Sun.COM 			}
18011767SAnurag.Maskey@Sun.COM 
181*12576SAnurag.Maskey@Oracle.COM 			if ((netmask = (struct sockaddr *)getaddr(RTA_NETMASK,
182*12576SAnurag.Maskey@Oracle.COM 			    ifa->ifam_addrs, addrs)) == NULL)
183*12576SAnurag.Maskey@Oracle.COM 				break;
184*12576SAnurag.Maskey@Oracle.COM 
18511767SAnurag.Maskey@Sun.COM 			if ((addr_dl = (struct sockaddr_dl *)getaddr
18611767SAnurag.Maskey@Sun.COM 			    (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
18711767SAnurag.Maskey@Sun.COM 				break;
18811767SAnurag.Maskey@Sun.COM 			/*
18911767SAnurag.Maskey@Sun.COM 			 * We don't use the lladdr in this structure so we can
19011767SAnurag.Maskey@Sun.COM 			 * run over it.
19111767SAnurag.Maskey@Sun.COM 			 */
19211767SAnurag.Maskey@Sun.COM 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
19311767SAnurag.Maskey@Sun.COM 			if_name = addr_dl->sdl_data; /* no lifnum */
19411767SAnurag.Maskey@Sun.COM 
19511767SAnurag.Maskey@Sun.COM 			if (ifa->ifam_index == 0) {
19611767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "tossing index 0 message");
19711767SAnurag.Maskey@Sun.COM 				break;
19811767SAnurag.Maskey@Sun.COM 			}
19911767SAnurag.Maskey@Sun.COM 			if (ifa->ifam_type != rtm->rtm_type) {
20011767SAnurag.Maskey@Sun.COM 				nlog(LOG_INFO,
20111767SAnurag.Maskey@Sun.COM 				    "routing_events_v4: unhandled type %d",
20211767SAnurag.Maskey@Sun.COM 				    ifa->ifam_type);
20311767SAnurag.Maskey@Sun.COM 				break;
20411767SAnurag.Maskey@Sun.COM 			}
20511767SAnurag.Maskey@Sun.COM 
206*12576SAnurag.Maskey@Oracle.COM 			printaddrs(ifa->ifam_addrs, addrs);
207*12576SAnurag.Maskey@Oracle.COM 
20811767SAnurag.Maskey@Sun.COM 			/* Create and enqueue IF_STATE event */
20911767SAnurag.Maskey@Sun.COM 			ip_event = nwamd_event_init_if_state(if_name,
21011767SAnurag.Maskey@Sun.COM 			    ifa->ifam_flags,
21111767SAnurag.Maskey@Sun.COM 			    (rtm->rtm_type == RTM_NEWADDR ||
21211767SAnurag.Maskey@Sun.COM 			    rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
213*12576SAnurag.Maskey@Oracle.COM 			    addr, netmask);
21411767SAnurag.Maskey@Sun.COM 			if (ip_event != NULL)
21511767SAnurag.Maskey@Sun.COM 				nwamd_event_enqueue(ip_event);
21611767SAnurag.Maskey@Sun.COM 			break;
21711767SAnurag.Maskey@Sun.COM 		}
21811767SAnurag.Maskey@Sun.COM 	}
21911767SAnurag.Maskey@Sun.COM 	/* NOTREACHED */
22011767SAnurag.Maskey@Sun.COM 	return (NULL);
22111767SAnurag.Maskey@Sun.COM }
22211767SAnurag.Maskey@Sun.COM 
22311767SAnurag.Maskey@Sun.COM /* ARGSUSED0 */
22411767SAnurag.Maskey@Sun.COM static void *
routing_events_v6(void * arg)22511767SAnurag.Maskey@Sun.COM routing_events_v6(void *arg)
22611767SAnurag.Maskey@Sun.COM {
22711767SAnurag.Maskey@Sun.COM 	int n;
22811767SAnurag.Maskey@Sun.COM 	union rtm_buf buffer;
22911767SAnurag.Maskey@Sun.COM 	struct rt_msghdr *rtm;
23011767SAnurag.Maskey@Sun.COM 	struct ifa_msghdr *ifa;
23111767SAnurag.Maskey@Sun.COM 	char *addrs, *if_name;
23211767SAnurag.Maskey@Sun.COM 	struct sockaddr_dl *addr_dl;
233*12576SAnurag.Maskey@Oracle.COM 	struct sockaddr *addr, *netmask;
23411767SAnurag.Maskey@Sun.COM 	nwamd_event_t ip_event;
23511767SAnurag.Maskey@Sun.COM 
23611767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "v6 routing socket %d", v6_sock);
23711767SAnurag.Maskey@Sun.COM 
23811767SAnurag.Maskey@Sun.COM 	for (;;) {
23911767SAnurag.Maskey@Sun.COM 
24011767SAnurag.Maskey@Sun.COM 		rtm = &buffer.r.rtm;
24111767SAnurag.Maskey@Sun.COM 		n = read(v6_sock, &buffer, sizeof (buffer));
24211767SAnurag.Maskey@Sun.COM 		if (n == -1 && errno == EAGAIN) {
24311767SAnurag.Maskey@Sun.COM 			continue;
24411767SAnurag.Maskey@Sun.COM 		} else if (n == -1) {
24511767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "error reading routing socket "
24611767SAnurag.Maskey@Sun.COM 			    "%d: %m", v6_sock);
24711767SAnurag.Maskey@Sun.COM 			/* Low likelihood.  What's recovery path?  */
24811767SAnurag.Maskey@Sun.COM 			continue;
24911767SAnurag.Maskey@Sun.COM 		}
25011767SAnurag.Maskey@Sun.COM 
25111767SAnurag.Maskey@Sun.COM 		if (rtm->rtm_msglen < n) {
25211767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "only read %d bytes from "
25311767SAnurag.Maskey@Sun.COM 			    "routing socket but message claims to be "
25411767SAnurag.Maskey@Sun.COM 			    "of length %d", rtm->rtm_msglen);
25511767SAnurag.Maskey@Sun.COM 			continue;
25611767SAnurag.Maskey@Sun.COM 		}
25711767SAnurag.Maskey@Sun.COM 
25811767SAnurag.Maskey@Sun.COM 		if (rtm->rtm_version != RTM_VERSION) {
25911767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "tossing routing message of "
26011767SAnurag.Maskey@Sun.COM 			    "version %d type %d", rtm->rtm_version,
26111767SAnurag.Maskey@Sun.COM 			    rtm->rtm_type);
26211767SAnurag.Maskey@Sun.COM 			continue;
26311767SAnurag.Maskey@Sun.COM 		}
26411767SAnurag.Maskey@Sun.COM 
26511767SAnurag.Maskey@Sun.COM 		if (rtm->rtm_msglen != n) {
26611767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "routing message of %d size came from "
26711767SAnurag.Maskey@Sun.COM 			    "read of %d on socket %d", rtm->rtm_msglen,
26811767SAnurag.Maskey@Sun.COM 			    n, v6_sock);
26911767SAnurag.Maskey@Sun.COM 		}
27011767SAnurag.Maskey@Sun.COM 
27111767SAnurag.Maskey@Sun.COM 		switch (rtm->rtm_type) {
27211767SAnurag.Maskey@Sun.COM 		case RTM_NEWADDR:
27311767SAnurag.Maskey@Sun.COM 		case RTM_DELADDR:
27411767SAnurag.Maskey@Sun.COM 		case RTM_CHGADDR:
27511767SAnurag.Maskey@Sun.COM 		case RTM_FREEADDR:
27611767SAnurag.Maskey@Sun.COM 
27711767SAnurag.Maskey@Sun.COM 			ifa = (void *)rtm;
27811767SAnurag.Maskey@Sun.COM 			addrs = (char *)ifa + sizeof (*ifa);
27911767SAnurag.Maskey@Sun.COM 
28011767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "v6 routing message %s: "
28111767SAnurag.Maskey@Sun.COM 			    "index %d flags %x", rtmtype_str(rtm->rtm_type),
28211767SAnurag.Maskey@Sun.COM 			    ifa->ifam_index, ifa->ifam_flags);
28311767SAnurag.Maskey@Sun.COM 
28411767SAnurag.Maskey@Sun.COM 			if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
28511767SAnurag.Maskey@Sun.COM 			    ifa->ifam_addrs, addrs)) == NULL)
28611767SAnurag.Maskey@Sun.COM 				break;
28711767SAnurag.Maskey@Sun.COM 
288*12576SAnurag.Maskey@Oracle.COM 			/* Ignore routing socket messages for :: & linklocal */
289*12576SAnurag.Maskey@Oracle.COM 			/*LINTED*/
290*12576SAnurag.Maskey@Oracle.COM 			if (IN6_IS_ADDR_UNSPECIFIED(
291*12576SAnurag.Maskey@Oracle.COM 			    &((struct sockaddr_in6 *)addr)->sin6_addr)) {
292*12576SAnurag.Maskey@Oracle.COM 				nlog(LOG_INFO, "routing_events_v6: "
293*12576SAnurag.Maskey@Oracle.COM 				    "tossing message for ::");
294*12576SAnurag.Maskey@Oracle.COM 				break;
295*12576SAnurag.Maskey@Oracle.COM 			}
29611767SAnurag.Maskey@Sun.COM 			/*LINTED*/
29711767SAnurag.Maskey@Sun.COM 			if (IN6_IS_ADDR_LINKLOCAL(
29811767SAnurag.Maskey@Sun.COM 			    &((struct sockaddr_in6 *)addr)->sin6_addr)) {
29911767SAnurag.Maskey@Sun.COM 				nlog(LOG_INFO, "routing_events_v6: "
30011767SAnurag.Maskey@Sun.COM 				    "tossing message for link local address");
30111767SAnurag.Maskey@Sun.COM 				break;
30211767SAnurag.Maskey@Sun.COM 			}
30311767SAnurag.Maskey@Sun.COM 
304*12576SAnurag.Maskey@Oracle.COM 			if ((netmask =
305*12576SAnurag.Maskey@Oracle.COM 			    (struct sockaddr *)getaddr(RTA_NETMASK,
306*12576SAnurag.Maskey@Oracle.COM 			    ifa->ifam_addrs, addrs)) == NULL)
307*12576SAnurag.Maskey@Oracle.COM 				break;
308*12576SAnurag.Maskey@Oracle.COM 
30911767SAnurag.Maskey@Sun.COM 			if ((addr_dl = (struct sockaddr_dl *)getaddr
31011767SAnurag.Maskey@Sun.COM 			    (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
31111767SAnurag.Maskey@Sun.COM 				break;
31211767SAnurag.Maskey@Sun.COM 			/*
31311767SAnurag.Maskey@Sun.COM 			 * We don't use the lladdr in this structure so we can
31411767SAnurag.Maskey@Sun.COM 			 * run over it.
31511767SAnurag.Maskey@Sun.COM 			 */
31611767SAnurag.Maskey@Sun.COM 			addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
31711767SAnurag.Maskey@Sun.COM 			if_name = addr_dl->sdl_data; /* no lifnum */
31811767SAnurag.Maskey@Sun.COM 
31911767SAnurag.Maskey@Sun.COM 			if (ifa->ifam_index == 0) {
32011767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "tossing index 0 message");
32111767SAnurag.Maskey@Sun.COM 				break;
32211767SAnurag.Maskey@Sun.COM 			}
32311767SAnurag.Maskey@Sun.COM 			if (ifa->ifam_type != rtm->rtm_type) {
32411767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG,
32511767SAnurag.Maskey@Sun.COM 				    "routing_events_v6: unhandled type %d",
32611767SAnurag.Maskey@Sun.COM 				    ifa->ifam_type);
32711767SAnurag.Maskey@Sun.COM 				break;
32811767SAnurag.Maskey@Sun.COM 			}
32911767SAnurag.Maskey@Sun.COM 
330*12576SAnurag.Maskey@Oracle.COM 			printaddrs(ifa->ifam_addrs, addrs);
331*12576SAnurag.Maskey@Oracle.COM 
33211767SAnurag.Maskey@Sun.COM 			/* Create and enqueue IF_STATE event */
33311767SAnurag.Maskey@Sun.COM 			ip_event = nwamd_event_init_if_state(if_name,
33411767SAnurag.Maskey@Sun.COM 			    ifa->ifam_flags,
33511767SAnurag.Maskey@Sun.COM 			    (rtm->rtm_type == RTM_NEWADDR ||
33611767SAnurag.Maskey@Sun.COM 			    rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
337*12576SAnurag.Maskey@Oracle.COM 			    addr, netmask);
33811767SAnurag.Maskey@Sun.COM 			if (ip_event != NULL)
33911767SAnurag.Maskey@Sun.COM 				nwamd_event_enqueue(ip_event);
34011767SAnurag.Maskey@Sun.COM 			break;
34111767SAnurag.Maskey@Sun.COM 
34211767SAnurag.Maskey@Sun.COM 		}
34311767SAnurag.Maskey@Sun.COM 	}
34411767SAnurag.Maskey@Sun.COM 	/* NOTREACHED */
34511767SAnurag.Maskey@Sun.COM 	return (NULL);
34611767SAnurag.Maskey@Sun.COM }
34711767SAnurag.Maskey@Sun.COM 
34811767SAnurag.Maskey@Sun.COM void
nwamd_routing_events_init(void)34911767SAnurag.Maskey@Sun.COM nwamd_routing_events_init(void)
35011767SAnurag.Maskey@Sun.COM {
35111767SAnurag.Maskey@Sun.COM 	pthread_attr_t attr;
35211767SAnurag.Maskey@Sun.COM 
35311767SAnurag.Maskey@Sun.COM 	/*
35411767SAnurag.Maskey@Sun.COM 	 * Initialize routing sockets here so that we know the routing threads
35511767SAnurag.Maskey@Sun.COM 	 * (and any requests to add a route) will be working with a valid socket
35611767SAnurag.Maskey@Sun.COM 	 * by the time we start handling events.
35711767SAnurag.Maskey@Sun.COM 	 */
35811767SAnurag.Maskey@Sun.COM 	v4_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET);
35911767SAnurag.Maskey@Sun.COM 	if (v4_sock == -1)
36011767SAnurag.Maskey@Sun.COM 		pfail("failed to open v4 routing socket: %m");
36111767SAnurag.Maskey@Sun.COM 
36211767SAnurag.Maskey@Sun.COM 	v6_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET6);
36311767SAnurag.Maskey@Sun.COM 	if (v6_sock == -1)
36411767SAnurag.Maskey@Sun.COM 		pfail("failed to open v6 routing socket: %m");
36511767SAnurag.Maskey@Sun.COM 
36611767SAnurag.Maskey@Sun.COM 	(void) pthread_attr_init(&attr);
36711767SAnurag.Maskey@Sun.COM 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
36811767SAnurag.Maskey@Sun.COM 	if (pthread_create(&v4_routing, &attr, routing_events_v4, NULL) != 0 ||
36911767SAnurag.Maskey@Sun.COM 	    pthread_create(&v6_routing, &attr, routing_events_v6, NULL) != 0)
37011767SAnurag.Maskey@Sun.COM 		pfail("routing thread creation failed");
37111767SAnurag.Maskey@Sun.COM 	(void) pthread_attr_destroy(&attr);
37211767SAnurag.Maskey@Sun.COM }
37311767SAnurag.Maskey@Sun.COM 
37411767SAnurag.Maskey@Sun.COM void
nwamd_routing_events_fini(void)37511767SAnurag.Maskey@Sun.COM nwamd_routing_events_fini(void)
37611767SAnurag.Maskey@Sun.COM {
37711767SAnurag.Maskey@Sun.COM 	(void) pthread_cancel(v4_routing);
37811767SAnurag.Maskey@Sun.COM 	(void) pthread_cancel(v6_routing);
37911767SAnurag.Maskey@Sun.COM }
38011767SAnurag.Maskey@Sun.COM 
38111767SAnurag.Maskey@Sun.COM void
nwamd_add_route(struct sockaddr * dest,struct sockaddr * mask,struct sockaddr * gateway,const char * ifname)38211767SAnurag.Maskey@Sun.COM nwamd_add_route(struct sockaddr *dest, struct sockaddr *mask,
38311767SAnurag.Maskey@Sun.COM     struct sockaddr *gateway, const char *ifname)
38411767SAnurag.Maskey@Sun.COM {
38511767SAnurag.Maskey@Sun.COM 	char rtbuf[RTMBUFSZ];
38611767SAnurag.Maskey@Sun.COM 	/* LINTED E_BAD_PTR_CAST_ALIGN */
38711767SAnurag.Maskey@Sun.COM 	struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
38811767SAnurag.Maskey@Sun.COM 	void *addrs = rtbuf + sizeof (struct rt_msghdr);
38911767SAnurag.Maskey@Sun.COM 	struct sockaddr_dl sdl;
39011767SAnurag.Maskey@Sun.COM 	int rlen, index;
39111767SAnurag.Maskey@Sun.COM 	int af;
39211767SAnurag.Maskey@Sun.COM 
39311767SAnurag.Maskey@Sun.COM 	af = gateway->sa_family;
39411767SAnurag.Maskey@Sun.COM 
395*12576SAnurag.Maskey@Oracle.COM 	/* retrieve the index value for the interface */
396*12576SAnurag.Maskey@Oracle.COM 	if ((index = if_nametoindex(ifname)) == 0) {
397*12576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "nwamd_add_route: if_nametoindex failed on %s",
398*12576SAnurag.Maskey@Oracle.COM 		    ifname);
39911767SAnurag.Maskey@Sun.COM 		return;
40011767SAnurag.Maskey@Sun.COM 	}
401*12576SAnurag.Maskey@Oracle.COM 
40211767SAnurag.Maskey@Sun.COM 	(void) bzero(&sdl, sizeof (struct sockaddr_dl));
40311767SAnurag.Maskey@Sun.COM 	sdl.sdl_family = AF_LINK;
40411767SAnurag.Maskey@Sun.COM 	sdl.sdl_index = index;
40511767SAnurag.Maskey@Sun.COM 
40611767SAnurag.Maskey@Sun.COM 	(void) bzero(rtm, RTMBUFSZ);
40711767SAnurag.Maskey@Sun.COM 	rtm->rtm_pid = getpid();
40811767SAnurag.Maskey@Sun.COM 	rtm->rtm_type = RTM_ADD;
40911767SAnurag.Maskey@Sun.COM 	rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
41011767SAnurag.Maskey@Sun.COM 	rtm->rtm_version = RTM_VERSION;
41111767SAnurag.Maskey@Sun.COM 	rtm->rtm_seq = ++seq;
41211767SAnurag.Maskey@Sun.COM 	rtm->rtm_msglen = sizeof (rtbuf);
41311767SAnurag.Maskey@Sun.COM 	setaddr(RTA_DST, &rtm->rtm_addrs, &addrs, dest);
41411767SAnurag.Maskey@Sun.COM 	setaddr(RTA_GATEWAY, &rtm->rtm_addrs, &addrs, gateway);
41511767SAnurag.Maskey@Sun.COM 	setaddr(RTA_NETMASK, &rtm->rtm_addrs, &addrs, mask);
41611767SAnurag.Maskey@Sun.COM 	setaddr(RTA_IFP, &rtm->rtm_addrs, &addrs, (struct sockaddr *)&sdl);
41711767SAnurag.Maskey@Sun.COM 
41811767SAnurag.Maskey@Sun.COM 	if ((rlen = write(af == AF_INET ? v4_sock : v6_sock,
41911767SAnurag.Maskey@Sun.COM 	    rtbuf, rtm->rtm_msglen)) < 0) {
42011767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_add_route: "
42111767SAnurag.Maskey@Sun.COM 		    "got error %s writing to routing socket", strerror(errno));
42211767SAnurag.Maskey@Sun.COM 	} else if (rlen < rtm->rtm_msglen) {
42311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_add_route: "
42411767SAnurag.Maskey@Sun.COM 		    "only wrote %d bytes of %d to routing socket\n",
42511767SAnurag.Maskey@Sun.COM 		    rlen, rtm->rtm_msglen);
42611767SAnurag.Maskey@Sun.COM 	}
42711767SAnurag.Maskey@Sun.COM }
42811767SAnurag.Maskey@Sun.COM 
42911767SAnurag.Maskey@Sun.COM static char *
printaddr(void ** address)43011767SAnurag.Maskey@Sun.COM printaddr(void **address)
43111767SAnurag.Maskey@Sun.COM {
43211767SAnurag.Maskey@Sun.COM 	static char buffer[80];
43311767SAnurag.Maskey@Sun.COM 	sa_family_t family = *(sa_family_t *)*address;
43411767SAnurag.Maskey@Sun.COM 	struct sockaddr_in *s4 = *address;
43511767SAnurag.Maskey@Sun.COM 	struct sockaddr_in6 *s6 = *address;
43611767SAnurag.Maskey@Sun.COM 	struct sockaddr_dl *dl = *address;
43711767SAnurag.Maskey@Sun.COM 
43811767SAnurag.Maskey@Sun.COM 	switch (family) {
43911767SAnurag.Maskey@Sun.COM 	case AF_UNSPEC:
44011767SAnurag.Maskey@Sun.COM 		(void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer,
44111767SAnurag.Maskey@Sun.COM 		    sizeof (buffer));
44211767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (*s4);
44311767SAnurag.Maskey@Sun.COM 		break;
44411767SAnurag.Maskey@Sun.COM 	case AF_INET:
44511767SAnurag.Maskey@Sun.COM 		(void) inet_ntop(AF_INET, &s4->sin_addr, buffer,
44611767SAnurag.Maskey@Sun.COM 		    sizeof (buffer));
44711767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (*s4);
44811767SAnurag.Maskey@Sun.COM 		break;
44911767SAnurag.Maskey@Sun.COM 	case AF_INET6:
45011767SAnurag.Maskey@Sun.COM 		(void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer,
45111767SAnurag.Maskey@Sun.COM 		    sizeof (buffer));
45211767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (*s6);
45311767SAnurag.Maskey@Sun.COM 		break;
45411767SAnurag.Maskey@Sun.COM 	case AF_LINK:
45511767SAnurag.Maskey@Sun.COM 		(void) snprintf(buffer, sizeof (buffer), "link %.*s",
45611767SAnurag.Maskey@Sun.COM 		    dl->sdl_nlen, dl->sdl_data);
45711767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (*dl);
45811767SAnurag.Maskey@Sun.COM 		break;
45911767SAnurag.Maskey@Sun.COM 	default:
46011767SAnurag.Maskey@Sun.COM 		/*
46111767SAnurag.Maskey@Sun.COM 		 * We can't reliably update the size of this thing
46211767SAnurag.Maskey@Sun.COM 		 * because we don't know what its type is.  So bump
46311767SAnurag.Maskey@Sun.COM 		 * it by a sockaddr_in and see what happens.  The
46411767SAnurag.Maskey@Sun.COM 		 * caller should really make sure this never happens.
46511767SAnurag.Maskey@Sun.COM 		 */
46611767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (*s4);
46711767SAnurag.Maskey@Sun.COM 		(void) snprintf(buffer, sizeof (buffer),
46811767SAnurag.Maskey@Sun.COM 		    "unknown address family %d", family);
46911767SAnurag.Maskey@Sun.COM 		break;
47011767SAnurag.Maskey@Sun.COM 	}
47111767SAnurag.Maskey@Sun.COM 	return (buffer);
47211767SAnurag.Maskey@Sun.COM }
47311767SAnurag.Maskey@Sun.COM 
47411767SAnurag.Maskey@Sun.COM static void
printaddrs(int mask,void * address)47511767SAnurag.Maskey@Sun.COM printaddrs(int mask, void *address)
47611767SAnurag.Maskey@Sun.COM {
47711767SAnurag.Maskey@Sun.COM 	if (mask == 0)
47811767SAnurag.Maskey@Sun.COM 		return;
47911767SAnurag.Maskey@Sun.COM 	if (mask & RTA_DST)
48011767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "destination address: %s", printaddr(&address));
48111767SAnurag.Maskey@Sun.COM 	if (mask & RTA_GATEWAY)
48211767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "gateway address: %s", printaddr(&address));
48311767SAnurag.Maskey@Sun.COM 	if (mask & RTA_NETMASK)
48411767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "netmask: %s", printaddr(&address));
48511767SAnurag.Maskey@Sun.COM 	if (mask & RTA_GENMASK)
48611767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "cloning mask: %s", printaddr(&address));
48711767SAnurag.Maskey@Sun.COM 	if (mask & RTA_IFP)
48811767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "interface name: %s", printaddr(&address));
48911767SAnurag.Maskey@Sun.COM 	if (mask & RTA_IFA)
49011767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "interface address: %s", printaddr(&address));
49111767SAnurag.Maskey@Sun.COM 	if (mask & RTA_AUTHOR)
49211767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "author: %s", printaddr(&address));
49311767SAnurag.Maskey@Sun.COM 	if (mask & RTA_BRD)
49411767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "broadcast address: %s", printaddr(&address));
49511767SAnurag.Maskey@Sun.COM }
49611767SAnurag.Maskey@Sun.COM 
49711767SAnurag.Maskey@Sun.COM static void
nextaddr(void ** address)49811767SAnurag.Maskey@Sun.COM nextaddr(void **address)
49911767SAnurag.Maskey@Sun.COM {
50011767SAnurag.Maskey@Sun.COM 	sa_family_t family = *(sa_family_t *)*address;
50111767SAnurag.Maskey@Sun.COM 
50211767SAnurag.Maskey@Sun.COM 	switch (family) {
50311767SAnurag.Maskey@Sun.COM 	case AF_UNSPEC:
50411767SAnurag.Maskey@Sun.COM 	case AF_INET:
50511767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (struct sockaddr_in);
50611767SAnurag.Maskey@Sun.COM 		break;
50711767SAnurag.Maskey@Sun.COM 	case AF_INET6:
50811767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (struct sockaddr_in6);
50911767SAnurag.Maskey@Sun.COM 		break;
51011767SAnurag.Maskey@Sun.COM 	case AF_LINK:
51111767SAnurag.Maskey@Sun.COM 		*address = (char *)*address + sizeof (struct sockaddr_dl);
51211767SAnurag.Maskey@Sun.COM 		break;
51311767SAnurag.Maskey@Sun.COM 	default:
51411767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "unknown af (%d) while parsing rtm", family);
51511767SAnurag.Maskey@Sun.COM 		break;
51611767SAnurag.Maskey@Sun.COM 	}
51711767SAnurag.Maskey@Sun.COM }
51811767SAnurag.Maskey@Sun.COM 
51911767SAnurag.Maskey@Sun.COM static void *
getaddr(int addrid,int mask,void * addresses)52011767SAnurag.Maskey@Sun.COM getaddr(int addrid, int mask, void *addresses)
52111767SAnurag.Maskey@Sun.COM {
52211767SAnurag.Maskey@Sun.COM 	int i;
52311767SAnurag.Maskey@Sun.COM 	void *p = addresses;
52411767SAnurag.Maskey@Sun.COM 
52511767SAnurag.Maskey@Sun.COM 	if ((mask & addrid) == 0)
52611767SAnurag.Maskey@Sun.COM 		return (NULL);
52711767SAnurag.Maskey@Sun.COM 
52811767SAnurag.Maskey@Sun.COM 	for (i = 1; i < addrid; i <<= 1) {
52911767SAnurag.Maskey@Sun.COM 		if (i & mask)
53011767SAnurag.Maskey@Sun.COM 			nextaddr(&p);
53111767SAnurag.Maskey@Sun.COM 	}
53211767SAnurag.Maskey@Sun.COM 	return (p);
53311767SAnurag.Maskey@Sun.COM }
53411767SAnurag.Maskey@Sun.COM 
53511767SAnurag.Maskey@Sun.COM static void
setaddr(int addrid,int * maskp,void * addressesp,struct sockaddr * address)53611767SAnurag.Maskey@Sun.COM setaddr(int addrid, int *maskp, void *addressesp, struct sockaddr *address)
53711767SAnurag.Maskey@Sun.COM {
53811767SAnurag.Maskey@Sun.COM 	struct sockaddr *p = *((struct sockaddr **)addressesp);
53911767SAnurag.Maskey@Sun.COM 
54011767SAnurag.Maskey@Sun.COM 	*maskp |= addrid;
54111767SAnurag.Maskey@Sun.COM 
54211767SAnurag.Maskey@Sun.COM 	switch (address->sa_family) {
54311767SAnurag.Maskey@Sun.COM 	case AF_INET:
54411767SAnurag.Maskey@Sun.COM 		(void) memcpy(p, address, sizeof (struct sockaddr_in));
54511767SAnurag.Maskey@Sun.COM 		break;
54611767SAnurag.Maskey@Sun.COM 	case AF_INET6:
54711767SAnurag.Maskey@Sun.COM 		(void) memcpy(p, address, sizeof (struct sockaddr_in6));
54811767SAnurag.Maskey@Sun.COM 		break;
54911767SAnurag.Maskey@Sun.COM 	case AF_LINK:
55011767SAnurag.Maskey@Sun.COM 		(void) memcpy(p, address, sizeof (struct sockaddr_dl));
55111767SAnurag.Maskey@Sun.COM 		break;
55211767SAnurag.Maskey@Sun.COM 	default:
55311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "setaddr: unknown af (%d) while setting addr",
55411767SAnurag.Maskey@Sun.COM 		    address->sa_family);
55511767SAnurag.Maskey@Sun.COM 		break;
55611767SAnurag.Maskey@Sun.COM 	}
55711767SAnurag.Maskey@Sun.COM 	nextaddr(addressesp);
55811767SAnurag.Maskey@Sun.COM }
559