routing_events.c revision 6ba597c56d749c61b4f783157f63196d7b2445f0
5aefb6555731130ca4fd295960123d71f2d21fe8rie/*
5aefb6555731130ca4fd295960123d71f2d21fe8rie * CDDL HEADER START
5aefb6555731130ca4fd295960123d71f2d21fe8rie *
5aefb6555731130ca4fd295960123d71f2d21fe8rie * The contents of this file are subject to the terms of the
5aefb6555731130ca4fd295960123d71f2d21fe8rie * Common Development and Distribution License (the "License").
5aefb6555731130ca4fd295960123d71f2d21fe8rie * You may not use this file except in compliance with the License.
5aefb6555731130ca4fd295960123d71f2d21fe8rie *
5aefb6555731130ca4fd295960123d71f2d21fe8rie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
5aefb6555731130ca4fd295960123d71f2d21fe8rie * or http://www.opensolaris.org/os/licensing.
5aefb6555731130ca4fd295960123d71f2d21fe8rie * See the License for the specific language governing permissions
5aefb6555731130ca4fd295960123d71f2d21fe8rie * and limitations under the License.
5aefb6555731130ca4fd295960123d71f2d21fe8rie *
5aefb6555731130ca4fd295960123d71f2d21fe8rie * When distributing Covered Code, include this CDDL HEADER in each
5aefb6555731130ca4fd295960123d71f2d21fe8rie * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
5aefb6555731130ca4fd295960123d71f2d21fe8rie * If applicable, add the following below this CDDL HEADER, with the
5aefb6555731130ca4fd295960123d71f2d21fe8rie * fields enclosed by brackets "[]" replaced with your own identifying
5aefb6555731130ca4fd295960123d71f2d21fe8rie * information: Portions Copyright [yyyy] [name of copyright owner]
5aefb6555731130ca4fd295960123d71f2d21fe8rie *
5aefb6555731130ca4fd295960123d71f2d21fe8rie * CDDL HEADER END
5aefb6555731130ca4fd295960123d71f2d21fe8rie */
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie/*
ba2be53024c0b999e74ba9adcd7d80fec5df8c57ab * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5aefb6555731130ca4fd295960123d71f2d21fe8rie * Use is subject to license terms.
5aefb6555731130ca4fd295960123d71f2d21fe8rie */
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <arpa/inet.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <assert.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <errno.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <fcntl.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <net/if.h>
ba2be53024c0b999e74ba9adcd7d80fec5df8c57ab#include <net/route.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <pthread.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <stdio.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <stdlib.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <string.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <strings.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <sys/fcntl.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <unistd.h>
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie#include <inetcfg.h>
981a172d53aeb81520fcfecf6ab2615277c7bd18ab#include <libnwam.h>
981a172d53aeb81520fcfecf6ab2615277c7bd18ab#include "events.h"
981a172d53aeb81520fcfecf6ab2615277c7bd18ab#include "ncp.h"
981a172d53aeb81520fcfecf6ab2615277c7bd18ab#include "ncu.h"
981a172d53aeb81520fcfecf6ab2615277c7bd18ab#include "util.h"
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab/*
981a172d53aeb81520fcfecf6ab2615277c7bd18ab * routing_events.c - this file contains routines to retrieve routing socket
981a172d53aeb81520fcfecf6ab2615277c7bd18ab * events and package them for high level processing.
981a172d53aeb81520fcfecf6ab2615277c7bd18ab */
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab#define RTMBUFSZ sizeof (struct rt_msghdr) + \
981a172d53aeb81520fcfecf6ab2615277c7bd18ab (RTAX_MAX * sizeof (struct sockaddr_storage))
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic void printaddrs(int, void *);
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic char *printaddr(void **);
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic void *getaddr(int, int, void *);
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic void setaddr(int, int *, void *, struct sockaddr *);
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18abunion rtm_buf
981a172d53aeb81520fcfecf6ab2615277c7bd18ab{
981a172d53aeb81520fcfecf6ab2615277c7bd18ab /* Routing information. */
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct
981a172d53aeb81520fcfecf6ab2615277c7bd18ab {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct rt_msghdr rtm;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct sockaddr_storage addr[RTAX_MAX];
981a172d53aeb81520fcfecf6ab2615277c7bd18ab } r;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab /* Interface information. */
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct
981a172d53aeb81520fcfecf6ab2615277c7bd18ab {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct if_msghdr ifm;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct sockaddr_storage addr[RTAX_MAX];
981a172d53aeb81520fcfecf6ab2615277c7bd18ab } im;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab /* Interface address information. */
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct
981a172d53aeb81520fcfecf6ab2615277c7bd18ab {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct ifa_msghdr ifa;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab struct sockaddr_storage addr[RTAX_MAX];
981a172d53aeb81520fcfecf6ab2615277c7bd18ab } ia;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab};
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic int v4_sock = -1;
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic int v6_sock = -1;
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic pthread_t v4_routing, v6_routing;
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic int seq = 0;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18abstatic const char *
981a172d53aeb81520fcfecf6ab2615277c7bd18abrtmtype_str(int type)
981a172d53aeb81520fcfecf6ab2615277c7bd18ab{
981a172d53aeb81520fcfecf6ab2615277c7bd18ab static char typestr[12]; /* strlen("type ") + enough for an int */
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab switch (type) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab case RTM_NEWADDR:
981a172d53aeb81520fcfecf6ab2615277c7bd18ab return ("NEWADDR");
981a172d53aeb81520fcfecf6ab2615277c7bd18ab case RTM_DELADDR:
981a172d53aeb81520fcfecf6ab2615277c7bd18ab return ("DELADDR");
981a172d53aeb81520fcfecf6ab2615277c7bd18ab case RTM_CHGADDR:
5aefb6555731130ca4fd295960123d71f2d21fe8rie return ("CHGADDR");
981a172d53aeb81520fcfecf6ab2615277c7bd18ab case RTM_FREEADDR:
5aefb6555731130ca4fd295960123d71f2d21fe8rie return ("FREEADDR");
5aefb6555731130ca4fd295960123d71f2d21fe8rie case RTM_IFINFO:
5aefb6555731130ca4fd295960123d71f2d21fe8rie return ("IFINFO");
f5a18a30a06b60eec275589214da939abbaa99d9rie default:
5aefb6555731130ca4fd295960123d71f2d21fe8rie (void) snprintf(typestr, sizeof (typestr), "type %d", type);
5aefb6555731130ca4fd295960123d71f2d21fe8rie return (typestr);
5aefb6555731130ca4fd295960123d71f2d21fe8rie }
31fdd7ca2d295948f9f1bcc2a1178c66467bca63ab}
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie/* ARGSUSED0 */
5aefb6555731130ca4fd295960123d71f2d21fe8riestatic void *
5aefb6555731130ca4fd295960123d71f2d21fe8rierouting_events_v4(void *arg)
5aefb6555731130ca4fd295960123d71f2d21fe8rie{
5aefb6555731130ca4fd295960123d71f2d21fe8rie int n;
5aefb6555731130ca4fd295960123d71f2d21fe8rie union rtm_buf buffer;
5aefb6555731130ca4fd295960123d71f2d21fe8rie struct rt_msghdr *rtm;
5aefb6555731130ca4fd295960123d71f2d21fe8rie struct ifa_msghdr *ifa;
5aefb6555731130ca4fd295960123d71f2d21fe8rie struct if_msghdr *ifm;
5aefb6555731130ca4fd295960123d71f2d21fe8rie char *addrs, *if_name;
5aefb6555731130ca4fd295960123d71f2d21fe8rie struct sockaddr_dl *addr_dl;
5aefb6555731130ca4fd295960123d71f2d21fe8rie struct sockaddr *addr;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab nwamd_event_t ip_event;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab nlog(LOG_DEBUG, "v4 routing socket %d", v4_sock);
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab for (;;) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab rtm = &buffer.r.rtm;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab n = read(v4_sock, &buffer, sizeof (buffer));
981a172d53aeb81520fcfecf6ab2615277c7bd18ab if (n == -1 && errno == EAGAIN) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab continue;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab } else if (n == -1) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab nlog(LOG_ERR, "error reading routing socket "
981a172d53aeb81520fcfecf6ab2615277c7bd18ab "%d: %m", v4_sock);
981a172d53aeb81520fcfecf6ab2615277c7bd18ab /* Low likelihood. What's recovery path? */
981a172d53aeb81520fcfecf6ab2615277c7bd18ab continue;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab }
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab if (rtm->rtm_msglen < n) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab nlog(LOG_ERR, "only read %d bytes from "
981a172d53aeb81520fcfecf6ab2615277c7bd18ab "routing socket but message claims to be "
981a172d53aeb81520fcfecf6ab2615277c7bd18ab "of length %d", rtm->rtm_msglen);
981a172d53aeb81520fcfecf6ab2615277c7bd18ab continue;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab }
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab if (rtm->rtm_version != RTM_VERSION) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab nlog(LOG_ERR, "tossing routing message of "
981a172d53aeb81520fcfecf6ab2615277c7bd18ab "version %d type %d", rtm->rtm_version,
981a172d53aeb81520fcfecf6ab2615277c7bd18ab rtm->rtm_type);
981a172d53aeb81520fcfecf6ab2615277c7bd18ab continue;
981a172d53aeb81520fcfecf6ab2615277c7bd18ab }
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab if (rtm->rtm_msglen != n) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab nlog(LOG_DEBUG, "routing message of %d size came from "
981a172d53aeb81520fcfecf6ab2615277c7bd18ab "read of %d on socket %d", rtm->rtm_msglen,
981a172d53aeb81520fcfecf6ab2615277c7bd18ab n, v4_sock);
981a172d53aeb81520fcfecf6ab2615277c7bd18ab }
981a172d53aeb81520fcfecf6ab2615277c7bd18ab
5aefb6555731130ca4fd295960123d71f2d21fe8rie switch (rtm->rtm_type) {
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab case RTM_NEWADDR:
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab case RTM_DELADDR:
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab case RTM_CHGADDR:
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab case RTM_FREEADDR:
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab ifa = (void *)rtm;
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab addrs = (char *)ifa + sizeof (*ifa);
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab nlog(LOG_DEBUG, "v4 routing message %s: "
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab "index %d flags %x", rtmtype_str(rtm->rtm_type),
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab ifa->ifam_index, ifa->ifam_flags);
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab printaddrs(ifa->ifam_addrs, addrs);
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
5aefb6555731130ca4fd295960123d71f2d21fe8rie ifa->ifam_addrs, addrs)) == NULL)
5aefb6555731130ca4fd295960123d71f2d21fe8rie break;
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie /* Ignore routing socket messages for 0.0.0.0 */
5aefb6555731130ca4fd295960123d71f2d21fe8rie /*LINTED*/
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab if (((struct sockaddr_in *)addr)->sin_addr.s_addr
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab == INADDR_ANY) {
5aefb6555731130ca4fd295960123d71f2d21fe8rie nlog(LOG_DEBUG, "routing_events_v4: "
5aefb6555731130ca4fd295960123d71f2d21fe8rie "tossing message for 0.0.0.0");
5aefb6555731130ca4fd295960123d71f2d21fe8rie break;
5aefb6555731130ca4fd295960123d71f2d21fe8rie }
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie if ((addr_dl = (struct sockaddr_dl *)getaddr
5aefb6555731130ca4fd295960123d71f2d21fe8rie (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
5aefb6555731130ca4fd295960123d71f2d21fe8rie break;
5aefb6555731130ca4fd295960123d71f2d21fe8rie /*
5aefb6555731130ca4fd295960123d71f2d21fe8rie * We don't use the lladdr in this structure so we can
5aefb6555731130ca4fd295960123d71f2d21fe8rie * run over it.
5aefb6555731130ca4fd295960123d71f2d21fe8rie */
5aefb6555731130ca4fd295960123d71f2d21fe8rie addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
5aefb6555731130ca4fd295960123d71f2d21fe8rie if_name = addr_dl->sdl_data; /* no lifnum */
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie if (ifa->ifam_index == 0) {
5aefb6555731130ca4fd295960123d71f2d21fe8rie nlog(LOG_DEBUG, "tossing index 0 message");
5aefb6555731130ca4fd295960123d71f2d21fe8rie break;
5aefb6555731130ca4fd295960123d71f2d21fe8rie }
5aefb6555731130ca4fd295960123d71f2d21fe8rie if (ifa->ifam_type != rtm->rtm_type) {
5aefb6555731130ca4fd295960123d71f2d21fe8rie nlog(LOG_INFO,
5aefb6555731130ca4fd295960123d71f2d21fe8rie "routing_events_v4: unhandled type %d",
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab ifa->ifam_type);
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab break;
5aefb6555731130ca4fd295960123d71f2d21fe8rie }
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie /* Create and enqueue IF_STATE event */
5aefb6555731130ca4fd295960123d71f2d21fe8rie ip_event = nwamd_event_init_if_state(if_name,
5aefb6555731130ca4fd295960123d71f2d21fe8rie ifa->ifam_flags,
5aefb6555731130ca4fd295960123d71f2d21fe8rie (rtm->rtm_type == RTM_NEWADDR ||
5aefb6555731130ca4fd295960123d71f2d21fe8rie rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
5aefb6555731130ca4fd295960123d71f2d21fe8rie ifa->ifam_index, addr);
5aefb6555731130ca4fd295960123d71f2d21fe8rie if (ip_event != NULL)
5aefb6555731130ca4fd295960123d71f2d21fe8rie nwamd_event_enqueue(ip_event);
5aefb6555731130ca4fd295960123d71f2d21fe8rie break;
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie case RTM_IFINFO:
5aefb6555731130ca4fd295960123d71f2d21fe8rie
5aefb6555731130ca4fd295960123d71f2d21fe8rie ifm = (void *)rtm;
5aefb6555731130ca4fd295960123d71f2d21fe8rie addrs = (char *)ifm + sizeof (*ifm);
5aefb6555731130ca4fd295960123d71f2d21fe8rie nlog(LOG_DEBUG, "v4 routing message %s: "
5aefb6555731130ca4fd295960123d71f2d21fe8rie "index %d flags %x", rtmtype_str(rtm->rtm_type),
5aefb6555731130ca4fd295960123d71f2d21fe8rie ifm->ifm_index, ifm->ifm_flags);
5aefb6555731130ca4fd295960123d71f2d21fe8rie printaddrs(ifm->ifm_addrs, addrs);
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab if ((addr_dl = (struct sockaddr_dl *)getaddr(RTA_IFP,
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab ifm->ifm_addrs, addrs)) == NULL)
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab break;
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab /*
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab * We don't use the lladdr in this structure so we can
c6c9aed4d309e3d11be652b85e3bf8bb72f20c87ab * run over it.
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab */
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab if_name = addr_dl->sdl_data; /* no lifnum */
39773e466ff90ce703d7f52f3267d7e96c09c6f5ab
981a172d53aeb81520fcfecf6ab2615277c7bd18ab if (ifm->ifm_index == 0) {
981a172d53aeb81520fcfecf6ab2615277c7bd18ab nlog(LOG_DEBUG, "tossing index 0 message");
5aefb6555731130ca4fd295960123d71f2d21fe8rie break;
5aefb6555731130ca4fd295960123d71f2d21fe8rie }
5aefb6555731130ca4fd295960123d71f2d21fe8rie if (ifm->ifm_type != RTM_IFINFO) {
5aefb6555731130ca4fd295960123d71f2d21fe8rie nlog(LOG_DEBUG,
5aefb6555731130ca4fd295960123d71f2d21fe8rie "routing_events_v4: unhandled type %d",
5aefb6555731130ca4fd295960123d71f2d21fe8rie ifm->ifm_type);
break;
}
/* Create and enqueue IF_STATE event */
ip_event = nwamd_event_init_if_state(if_name,
ifm->ifm_flags, B_FALSE, ifm->ifm_index, NULL);
if (ip_event != NULL)
nwamd_event_enqueue(ip_event);
break;
default:
nlog(LOG_DEBUG, "v4 routing message %s discarded",
rtmtype_str(rtm->rtm_type));
break;
}
}
/* NOTREACHED */
return (NULL);
}
/* ARGSUSED0 */
static void *
routing_events_v6(void *arg)
{
int n;
union rtm_buf buffer;
struct rt_msghdr *rtm;
struct ifa_msghdr *ifa;
struct if_msghdr *ifm;
char *addrs, *if_name;
struct sockaddr_dl *addr_dl;
struct sockaddr *addr;
nwamd_event_t ip_event;
nlog(LOG_DEBUG, "v6 routing socket %d", v6_sock);
for (;;) {
rtm = &buffer.r.rtm;
n = read(v6_sock, &buffer, sizeof (buffer));
if (n == -1 && errno == EAGAIN) {
continue;
} else if (n == -1) {
nlog(LOG_ERR, "error reading routing socket "
"%d: %m", v6_sock);
/* Low likelihood. What's recovery path? */
continue;
}
if (rtm->rtm_msglen < n) {
nlog(LOG_ERR, "only read %d bytes from "
"routing socket but message claims to be "
"of length %d", rtm->rtm_msglen);
continue;
}
if (rtm->rtm_version != RTM_VERSION) {
nlog(LOG_ERR, "tossing routing message of "
"version %d type %d", rtm->rtm_version,
rtm->rtm_type);
continue;
}
if (rtm->rtm_msglen != n) {
nlog(LOG_DEBUG, "routing message of %d size came from "
"read of %d on socket %d", rtm->rtm_msglen,
n, v6_sock);
}
switch (rtm->rtm_type) {
case RTM_NEWADDR:
case RTM_DELADDR:
case RTM_CHGADDR:
case RTM_FREEADDR:
ifa = (void *)rtm;
addrs = (char *)ifa + sizeof (*ifa);
nlog(LOG_DEBUG, "v6 routing message %s: "
"index %d flags %x", rtmtype_str(rtm->rtm_type),
ifa->ifam_index, ifa->ifam_flags);
printaddrs(ifa->ifam_addrs, addrs);
if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
ifa->ifam_addrs, addrs)) == NULL)
break;
/* Ignore messages for link local address */
/*LINTED*/
if (IN6_IS_ADDR_LINKLOCAL(
&((struct sockaddr_in6 *)addr)->sin6_addr)) {
nlog(LOG_INFO, "routing_events_v6: "
"tossing message for link local address");
break;
}
if ((addr_dl = (struct sockaddr_dl *)getaddr
(RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
break;
/*
* We don't use the lladdr in this structure so we can
* run over it.
*/
addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
if_name = addr_dl->sdl_data; /* no lifnum */
if (ifa->ifam_index == 0) {
nlog(LOG_DEBUG, "tossing index 0 message");
break;
}
if (ifa->ifam_type != rtm->rtm_type) {
nlog(LOG_DEBUG,
"routing_events_v6: unhandled type %d",
ifa->ifam_type);
break;
}
/* Create and enqueue IF_STATE event */
ip_event = nwamd_event_init_if_state(if_name,
ifa->ifam_flags,
(rtm->rtm_type == RTM_NEWADDR ||
rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
ifa->ifam_index, addr);
if (ip_event != NULL)
nwamd_event_enqueue(ip_event);
break;
case RTM_IFINFO:
ifm = (void *)rtm;
addrs = (char *)ifm + sizeof (*ifm);
nlog(LOG_DEBUG, "v6 routing message %s: "
"index %d flags %x", rtmtype_str(rtm->rtm_type),
ifm->ifm_index, ifm->ifm_flags);
printaddrs(ifm->ifm_addrs, addrs);
if ((addr_dl = (struct sockaddr_dl *)getaddr(RTA_IFP,
ifm->ifm_addrs, addrs)) == NULL)
break;
/*
* We don't use the lladdr in this structure so we can
* run over it.
*/
addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
if_name = addr_dl->sdl_data; /* no lifnum */
if (ifm->ifm_index == 0) {
nlog(LOG_DEBUG, "tossing index 0 message");
break;
}
if (ifm->ifm_type != RTM_IFINFO) {
nlog(LOG_DEBUG,
"routing_events_v6: unhandled type %d",
ifm->ifm_type);
break;
}
/* Create and enqueue IF_STATE event */
ip_event = nwamd_event_init_if_state(if_name,
ifm->ifm_flags, B_FALSE, ifm->ifm_index, NULL);
if (ip_event != NULL)
nwamd_event_enqueue(ip_event);
break;
default:
nlog(LOG_DEBUG, "v6 routing message %s discarded",
rtmtype_str(rtm->rtm_type));
break;
}
}
/* NOTREACHED */
return (NULL);
}
void
nwamd_routing_events_init(void)
{
pthread_attr_t attr;
/*
* Initialize routing sockets here so that we know the routing threads
* (and any requests to add a route) will be working with a valid socket
* by the time we start handling events.
*/
v4_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET);
if (v4_sock == -1)
pfail("failed to open v4 routing socket: %m");
v6_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET6);
if (v6_sock == -1)
pfail("failed to open v6 routing socket: %m");
(void) pthread_attr_init(&attr);
(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&v4_routing, &attr, routing_events_v4, NULL) != 0 ||
pthread_create(&v6_routing, &attr, routing_events_v6, NULL) != 0)
pfail("routing thread creation failed");
(void) pthread_attr_destroy(&attr);
}
void
nwamd_routing_events_fini(void)
{
(void) pthread_cancel(v4_routing);
(void) pthread_cancel(v6_routing);
}
void
nwamd_add_route(struct sockaddr *dest, struct sockaddr *mask,
struct sockaddr *gateway, const char *ifname)
{
char rtbuf[RTMBUFSZ];
/* LINTED E_BAD_PTR_CAST_ALIGN */
struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
void *addrs = rtbuf + sizeof (struct rt_msghdr);
struct sockaddr_dl sdl;
icfg_if_t intf;
icfg_handle_t h;
int rlen, index;
int af;
af = gateway->sa_family;
/* set interface for default route to be associated with */
(void) strlcpy(intf.if_name, ifname, sizeof (intf.if_name));
intf.if_protocol = af;
if (icfg_open(&h, &intf) != ICFG_SUCCESS) {
nlog(LOG_ERR, "nwamd_add_route: "
"icfg_open failed on %s", ifname);
return;
}
if (icfg_get_index(h, &index) != ICFG_SUCCESS) {
nlog(LOG_ERR, "nwamd_add_route: "
"icfg_get_index failed on %s", ifname);
}
icfg_close(h);
(void) bzero(&sdl, sizeof (struct sockaddr_dl));
sdl.sdl_family = AF_LINK;
sdl.sdl_index = index;
(void) bzero(rtm, RTMBUFSZ);
rtm->rtm_pid = getpid();
rtm->rtm_type = RTM_ADD;
rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
rtm->rtm_version = RTM_VERSION;
rtm->rtm_seq = ++seq;
rtm->rtm_msglen = sizeof (rtbuf);
setaddr(RTA_DST, &rtm->rtm_addrs, &addrs, dest);
setaddr(RTA_GATEWAY, &rtm->rtm_addrs, &addrs, gateway);
setaddr(RTA_NETMASK, &rtm->rtm_addrs, &addrs, mask);
setaddr(RTA_IFP, &rtm->rtm_addrs, &addrs, (struct sockaddr *)&sdl);
if ((rlen = write(af == AF_INET ? v4_sock : v6_sock,
rtbuf, rtm->rtm_msglen)) < 0) {
nlog(LOG_ERR, "nwamd_add_route: "
"got error %s writing to routing socket", strerror(errno));
} else if (rlen < rtm->rtm_msglen) {
nlog(LOG_ERR, "nwamd_add_route: "
"only wrote %d bytes of %d to routing socket\n",
rlen, rtm->rtm_msglen);
}
}
static char *
printaddr(void **address)
{
static char buffer[80];
sa_family_t family = *(sa_family_t *)*address;
struct sockaddr_in *s4 = *address;
struct sockaddr_in6 *s6 = *address;
struct sockaddr_dl *dl = *address;
switch (family) {
case AF_UNSPEC:
(void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer,
sizeof (buffer));
*address = (char *)*address + sizeof (*s4);
break;
case AF_INET:
(void) inet_ntop(AF_INET, &s4->sin_addr, buffer,
sizeof (buffer));
*address = (char *)*address + sizeof (*s4);
break;
case AF_INET6:
(void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer,
sizeof (buffer));
*address = (char *)*address + sizeof (*s6);
break;
case AF_LINK:
(void) snprintf(buffer, sizeof (buffer), "link %.*s",
dl->sdl_nlen, dl->sdl_data);
*address = (char *)*address + sizeof (*dl);
break;
default:
/*
* We can't reliably update the size of this thing
* because we don't know what its type is. So bump
* it by a sockaddr_in and see what happens. The
* caller should really make sure this never happens.
*/
*address = (char *)*address + sizeof (*s4);
(void) snprintf(buffer, sizeof (buffer),
"unknown address family %d", family);
break;
}
return (buffer);
}
static void
printaddrs(int mask, void *address)
{
if (mask == 0)
return;
if (mask & RTA_DST)
nlog(LOG_DEBUG, "destination address: %s", printaddr(&address));
if (mask & RTA_GATEWAY)
nlog(LOG_DEBUG, "gateway address: %s", printaddr(&address));
if (mask & RTA_NETMASK)
nlog(LOG_DEBUG, "netmask: %s", printaddr(&address));
if (mask & RTA_GENMASK)
nlog(LOG_DEBUG, "cloning mask: %s", printaddr(&address));
if (mask & RTA_IFP)
nlog(LOG_DEBUG, "interface name: %s", printaddr(&address));
if (mask & RTA_IFA)
nlog(LOG_DEBUG, "interface address: %s", printaddr(&address));
if (mask & RTA_AUTHOR)
nlog(LOG_DEBUG, "author: %s", printaddr(&address));
if (mask & RTA_BRD)
nlog(LOG_DEBUG, "broadcast address: %s", printaddr(&address));
}
static void
nextaddr(void **address)
{
sa_family_t family = *(sa_family_t *)*address;
switch (family) {
case AF_UNSPEC:
case AF_INET:
*address = (char *)*address + sizeof (struct sockaddr_in);
break;
case AF_INET6:
*address = (char *)*address + sizeof (struct sockaddr_in6);
break;
case AF_LINK:
*address = (char *)*address + sizeof (struct sockaddr_dl);
break;
default:
nlog(LOG_ERR, "unknown af (%d) while parsing rtm", family);
break;
}
}
static void *
getaddr(int addrid, int mask, void *addresses)
{
int i;
void *p = addresses;
if ((mask & addrid) == 0)
return (NULL);
for (i = 1; i < addrid; i <<= 1) {
if (i & mask)
nextaddr(&p);
}
return (p);
}
static void
setaddr(int addrid, int *maskp, void *addressesp, struct sockaddr *address)
{
struct sockaddr *p = *((struct sockaddr **)addressesp);
*maskp |= addrid;
switch (address->sa_family) {
case AF_INET:
(void) memcpy(p, address, sizeof (struct sockaddr_in));
break;
case AF_INET6:
(void) memcpy(p, address, sizeof (struct sockaddr_in6));
break;
case AF_LINK:
(void) memcpy(p, address, sizeof (struct sockaddr_dl));
break;
default:
nlog(LOG_ERR, "setaddr: unknown af (%d) while setting addr",
address->sa_family);
break;
}
nextaddr(addressesp);
}