/*
* 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
*/
/*
*/
/*
* smbd NIC monitor.
*/
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <syslog.h>
#include "smbd.h"
/* Use this to stop monitoring */
/* Use this to refresh service instance */
static void smbd_nicmon_run_check(void);
static int smbd_nicmon_setup_rtsock(int);
static int smbd_nicmon_needscan(int);
static int smbd_nicmon_setup_eventpipe(int *, int *);
static void *smbd_nicmon_daemon(void *);
/*
* Start the nic monitor thread.
*/
int
{
int rc;
if (smb_nic_init() != SMB_NIC_SUCCESS)
return (-1);
if (rc != 0)
return (-1);
if (svc_fmri)
smbd_nicmon_caller_fmri = (char *)svc_fmri;
return (0);
}
void
smbd_nicmon_stop(void)
{
if (eventpipe_write < 0)
return;
smb_nic_fini();
}
int
smbd_nicmon_refresh(void)
{
if (smb_nic_init() != SMB_NIC_SUCCESS)
return (-1);
return (0);
}
/*
* The monitor is enabled unless it is explicitly
* disabled by setting smbd/nicmon_enable to false.
* smbd/nicmon_enable is not defined by default.
*/
static void
smbd_nicmon_run_check(void)
{
int rc;
"smbd_nicmon: smb_smf_scf_init failed");
return;
}
if (rc != SMBD_SMF_OK) {
"smbd_nicmon: smb_smf_create_service_pgroup failed");
return;
}
}
/*
* Setup routing socket for getting RTM messages.
*/
static int
{
int sd;
int flags;
"smbd_nicmon: routing socket failed: %d", errno);
return (-1);
}
"smbd_nicmon: fcntl F_GETFL failed: %d", errno);
return (-1);
}
"smbd_nicmon: fcntl F_SETFL failed: %d", errno);
return (-1);
}
return (sd);
}
static int
{
int need_if_scan = 0;
int nbytes;
/* Read as many messages as possible and try to empty the sockets */
for (;;) {
if (nbytes <= 0)
break;
continue;
if ((throttle % SMBD_NICMON_THROTTLE) == 0) {
"smbd_nicmon: short read: %d of %d",
}
++throttle;
continue;
}
case RTM_NEWADDR:
case RTM_DELADDR:
case RTM_IFINFO:
need_if_scan = 1;
break;
default:
break;
}
}
return (need_if_scan);
}
/*
* Create pipe for signal delivery and set up signal handlers.
*/
static int
{
"smbd_nicmon: event pipe failed: %d", errno);
return (-1);
}
return (0);
}
/*
* Create the global routing socket to monitor changes in NIC interfaces.
*
* Note: only supports AF_INET routing socket. Need to add AF_INET6 to
* support IPv6.
*/
/*ARGSUSED*/
static void *
{
static int rtsock_v4;
int i, nic_changed;
int rc;
return (NULL);
if (rc != 0)
return (NULL);
/*
* Listen for activity on any of the sockets.
* The delay before checking the rtsock will hopefully
* smooth things out when there is a lot of activity.
*/
for (;;) {
errno = 0;
nic_changed = 0;
continue;
if ((throttle % SMBD_NICMON_THROTTLE) == 0)
"smbd_nicmon: poll failed: %d", errno);
++throttle;
break;
}
for (i = 0; i < pollfd_num; i++) {
continue;
(void) sleep(SMBD_NICMON_DEBOUNCE);
}
goto done;
}
/*
* If the monitor is enabled and something has changed,
* refresh the registered SMF service.
*/
if (smbd_nicmon_enabled && nic_changed &&
if (smf_refresh_instance(smbd_nicmon_caller_fmri) != 0)
"smbd_nicmon: %s refresh failed",
}
}
done:
(void) close(eventpipe_read);
(void) close(eventpipe_write);
eventpipe_write = -1;
return (NULL);
}