events.c revision d71dbb732372504daff1f1783bc0d8864ce9bd50
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains routines to retrieve events from the system and package
* them for high level processing.
*
* struct np_event is the basic event structure. The np_event structure and
* its npe_name member are allocated using malloc(3c). free_event() frees both
* the npe_name member and the associated np_event structure.
*
* np_queue_add_event() and np_queue_get_event() provide functionality for
* adding events to a queue and blocking on that queue for an event.
*
* Functions of the form addevent_*() provide the mechanism to cook down a
* higher level event into an np_event and put it on the queue.
*
* routing_events() reads routing messages off of an IPv4 routing socket and
* by calling addevent_*() functions places appropriate events on the queue.
*
* start_event_collection() creates a thread to run routing_events() and one
* to run periodic_wireless_scan() in. Finally it does an initial collection
* of information from each interface currently known.
*/
#include <assert.h>
#include <errno.h>
#include <libsysevent.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <fcntl.h>
#include "defines.h"
#include "structures.h"
#include "functions.h"
#include "variables.h"
union rtm_buf
{
/* Routing information. */
struct
{
} r;
/* Interface information. */
struct
{
} im;
/* Interface address information. */
struct
{
struct ifa_msghdr ifa;
} ia;
};
void
free_event(struct np_event *e)
{
free(e);
}
void
np_queue_add_event(struct np_event *e)
{
(void) pthread_mutex_lock(&queue_mutex);
if (equeue_end != NULL) {
equeue_end->npe_next = e;
equeue_end = e;
} else {
equeue = equeue_end = e;
}
(void) pthread_cond_signal(&queue_cond);
(void) pthread_mutex_unlock(&queue_mutex);
}
/*
* Blocking getevent. This routine will block until there is an event for
* it to return.
*/
struct np_event *
np_queue_get_event(void)
{
(void) pthread_mutex_lock(&queue_mutex);
equeue_end = NULL;
(void) pthread_mutex_unlock(&queue_mutex);
return (rv);
}
const char *
{
switch (type) {
case EV_ROUTING:
return ("ROUTING");
case EV_SYS:
return ("SYS");
case EV_TIMER:
return ("TIMER");
case EV_SHUTDOWN:
return ("SHUTDOWN");
case EV_NEWADDR:
return ("NEWADDR");
default:
return ("unknown");
}
}
static void
{
struct np_event *e;
dprintf("addevent_routing_ifa");
if (ifa->ifam_index == 0) {
/* what is this? */
dprintf("tossing index 0 routing event");
return;
}
e = calloc(1, sizeof (*e));
if (e == NULL) {
return;
}
case RTM_NEWADDR:
e->npe_type = EV_NEWADDR;
free(e);
return;
}
dprintf("adding event type %s name %s to queue",
break;
default:
free(e);
dprintf("unhandled type in addevent_routing_ifa %d",
break;
}
}
static void
{
struct np_event *e;
dprintf("addevent_routing_msghdr");
/* what is this? */
dprintf("tossing index 0 routing event");
return;
}
case RTM_IFINFO:
e = calloc(1, sizeof (*e));
if (e == NULL) {
return;
}
e->npe_type = EV_ROUTING;
free(e);
return;
}
dprintf("adding event type %s name %s to queue",
break;
default:
dprintf("unhandled type in addevent_routing_msghdr %d",
break;
}
}
static const char *
rtmtype_str(int type)
{
switch (type) {
case RTM_ADD:
return ("ADD");
case RTM_DELETE:
return ("DELETE");
case RTM_NEWADDR:
return ("NEWADDR");
case RTM_DELADDR:
return ("DELADDR");
case RTM_IFINFO:
return ("IFINFO");
default:
type);
return (typestr);
}
}
/* ARGSUSED */
static void *
routing_events(void *arg)
{
int rtsock;
int n;
struct ifa_msghdr *ifa;
/*
* We use v4 interfaces as proxies for links so those are the only
* routing messages we need to listen to. Look at the comments in
* structures.h for more information about the split between the
* llp and interfaces.
*/
if (rtsock == -1) {
}
for (;;) {
struct sockaddr_dl *addr_dl;
continue;
} else if (n == -1) {
"%d: %m", rtsock);
/* Low likelihood. What's recovery path? */
continue;
}
if (rtm->rtm_msglen < n) {
"routing socket but message claims to be "
continue;
}
continue;
}
if (rtm->rtm_msglen != n) {
dprintf("routing message of %d size came from "
n, rtsock);
}
case RTM_NEWADDR:
dprintf("routing message NEWADDR: index %d flags %x",
break;
break;
dprintf("no interface struct for %s; ignoring "
break;
}
/* if no cached address, cache it */
dprintf("cached address %s for link %s",
}
break;
case RTM_IFINFO:
{
dprintf("routing message IFINFO: index %d flags %x",
break;
dprintf("no interface struct for %s; ignoring "
break;
}
/*
* Check for toggling of the IFF_RUNNING
* flag.
*
* On any change in the flag value, we
* turn off the DHCPFAILED and DHCPSTARTED
* flags; the change in the RUNNING state
* indicates a "fresh start" for the
* interface, so we should try dhcp again.
*
* Ignore specific IFF_RUNNING changes for
* wireless interfaces; their semantics are
* a bit different (either the flag is always
* on, or, with newer drivers, it indicates
* whether or not they are connected to an AP).
*
* For wired interfaces, if the interface was
* not plugged in and now it is, start info
* collection.
*
* If it was plugged in and now it is
* unplugged, generate an event.
*
* XXX We probably need a lock to protect
* if_flags setting and getting.
*/
}
break;
if (!plugged_in &&
} else if (plugged_in &&
}
break;
}
default:
dprintf("routing message %s socket %d discarded",
break;
}
}
/* NOTREACHED */
return (NULL);
}
/* return B_TRUE if sin_family and sin_addr are the same, B_FALSE if not */
static boolean_t
{
return (B_FALSE);
case AF_INET:
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* LINTED E_BAD_PTR_CAST_ALIGN */
case AF_INET6:
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* LINTED E_BAD_PTR_CAST_ALIGN */
return
default:
return (B_FALSE);
}
}
/*
* Duplicate a sockaddr. Caller will be responsible for freeing memory when it
* is no longer needed. Currently only supports AF_INET and AF_INET6
* (returns NULL otherwise).
*/
static struct sockaddr *
{
case AF_INET:
return (NULL);
}
/* LINTED E_BAD_PTR_CAST_ALIGN */
case AF_INET6:
return (NULL);
}
/* LINTED E_BAD_PTR_CAST_ALIGN */
default:
return (NULL);
}
}
static char *
{
static char buffer[80];
switch (family) {
case AF_UNSPEC:
sizeof (buffer));
break;
case AF_INET:
sizeof (buffer));
break;
case AF_INET6:
sizeof (buffer));
break;
case AF_LINK:
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.
*/
"unknown address family %d", family);
break;
}
return (buffer);
}
static void
{
if (mask == 0)
return;
if (mask & RTA_GATEWAY)
if (mask & RTA_NETMASK)
if (mask & RTA_GENMASK)
if (mask & RTA_AUTHOR)
}
static void
{
switch (family) {
case AF_UNSPEC:
case AF_INET:
break;
case AF_INET6:
break;
case AF_LINK:
break;
default:
break;
}
}
static void *
{
int i;
void *p = address;
return (NULL);
if (i & mask)
nextaddr(&p);
}
return (p);
}
start_event_collection(void)
{
int err;
/*
* have to change this.
*/
} else {
}
} else {
}
return (B_TRUE);
}