1148c5f43SAlan Wright /* 2148c5f43SAlan Wright * CDDL HEADER START 3148c5f43SAlan Wright * 4148c5f43SAlan Wright * The contents of this file are subject to the terms of the 5148c5f43SAlan Wright * Common Development and Distribution License (the "License"). 6148c5f43SAlan Wright * You may not use this file except in compliance with the License. 7148c5f43SAlan Wright * 8148c5f43SAlan Wright * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9148c5f43SAlan Wright * or http://www.opensolaris.org/os/licensing. 10148c5f43SAlan Wright * See the License for the specific language governing permissions 11148c5f43SAlan Wright * and limitations under the License. 12148c5f43SAlan Wright * 13148c5f43SAlan Wright * When distributing Covered Code, include this CDDL HEADER in each 14148c5f43SAlan Wright * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15148c5f43SAlan Wright * If applicable, add the following below this CDDL HEADER, with the 16148c5f43SAlan Wright * fields enclosed by brackets "[]" replaced with your own identifying 17148c5f43SAlan Wright * information: Portions Copyright [yyyy] [name of copyright owner] 18148c5f43SAlan Wright * 19148c5f43SAlan Wright * CDDL HEADER END 20148c5f43SAlan Wright */ 21148c5f43SAlan Wright /* 22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23148c5f43SAlan Wright */ 24148c5f43SAlan Wright 25148c5f43SAlan Wright /* 26148c5f43SAlan Wright * smbd NIC monitor. 27148c5f43SAlan Wright */ 28148c5f43SAlan Wright 29148c5f43SAlan Wright #include <sys/types.h> 30148c5f43SAlan Wright #include <stdlib.h> 31148c5f43SAlan Wright #include <errno.h> 32148c5f43SAlan Wright #include <string.h> 33148c5f43SAlan Wright #include <unistd.h> 34148c5f43SAlan Wright #include <signal.h> 35148c5f43SAlan Wright #include <stdio.h> 36148c5f43SAlan Wright #include <net/if.h> 37148c5f43SAlan Wright #include <net/route.h> 38148c5f43SAlan Wright #include <sys/sockio.h> 39148c5f43SAlan Wright #include <sys/socket.h> 40148c5f43SAlan Wright #include <netinet/in.h> 41148c5f43SAlan Wright #include <arpa/inet.h> 42148c5f43SAlan Wright #include <fcntl.h> 43148c5f43SAlan Wright #include <pthread.h> 44148c5f43SAlan Wright #include <syslog.h> 45148c5f43SAlan Wright #include <smbsrv/libsmb.h> 46148c5f43SAlan Wright #include "smbd.h" 47148c5f43SAlan Wright 48148c5f43SAlan Wright #define SMBD_NICMON_ENABLE "nicmon_enable" 49148c5f43SAlan Wright #define SMBD_NICMON_THROTTLE 100 50148c5f43SAlan Wright #define SMBD_NICMON_DEBOUNCE 2 51148c5f43SAlan Wright 52148c5f43SAlan Wright extern smbd_t smbd; 53148c5f43SAlan Wright 54148c5f43SAlan Wright static boolean_t smbd_nicmon_enabled = B_TRUE; 55148c5f43SAlan Wright 56148c5f43SAlan Wright /* Use this to stop monitoring */ 57148c5f43SAlan Wright static int eventpipe_write = -1; 58148c5f43SAlan Wright 59148c5f43SAlan Wright /* Use this to refresh service instance */ 60148c5f43SAlan Wright static char *smbd_nicmon_caller_fmri = NULL; 61148c5f43SAlan Wright 62148c5f43SAlan Wright static void smbd_nicmon_run_check(void); 63148c5f43SAlan Wright static int smbd_nicmon_setup_rtsock(int); 64148c5f43SAlan Wright static int smbd_nicmon_needscan(int); 65148c5f43SAlan Wright static int smbd_nicmon_setup_eventpipe(int *, int *); 66148c5f43SAlan Wright static void *smbd_nicmon_daemon(void *); 67148c5f43SAlan Wright 68148c5f43SAlan Wright /* 69148c5f43SAlan Wright * Start the nic monitor thread. 70148c5f43SAlan Wright */ 71148c5f43SAlan Wright int 72148c5f43SAlan Wright smbd_nicmon_start(const char *svc_fmri) 73148c5f43SAlan Wright { 74148c5f43SAlan Wright pthread_t smbd_nicmon_tid; 75148c5f43SAlan Wright int rc; 76148c5f43SAlan Wright 77148c5f43SAlan Wright if (smb_nic_init() != SMB_NIC_SUCCESS) 78148c5f43SAlan Wright return (-1); 79148c5f43SAlan Wright 80148c5f43SAlan Wright rc = pthread_create(&smbd_nicmon_tid, NULL, smbd_nicmon_daemon, NULL); 81148c5f43SAlan Wright if (rc != 0) 82148c5f43SAlan Wright return (-1); 83148c5f43SAlan Wright 84148c5f43SAlan Wright if (svc_fmri) 85148c5f43SAlan Wright smbd_nicmon_caller_fmri = (char *)svc_fmri; 86148c5f43SAlan Wright 87148c5f43SAlan Wright smbd_nicmon_run_check(); 88148c5f43SAlan Wright return (0); 89148c5f43SAlan Wright } 90148c5f43SAlan Wright 91148c5f43SAlan Wright void 92148c5f43SAlan Wright smbd_nicmon_stop(void) 93148c5f43SAlan Wright { 94148c5f43SAlan Wright uchar_t buf = 1; 95148c5f43SAlan Wright 96148c5f43SAlan Wright if (eventpipe_write < 0) 97148c5f43SAlan Wright return; 98148c5f43SAlan Wright 99148c5f43SAlan Wright (void) write(eventpipe_write, &buf, sizeof (buf)); 100148c5f43SAlan Wright smbd_nicmon_caller_fmri = NULL; 101148c5f43SAlan Wright smb_nic_fini(); 102148c5f43SAlan Wright } 103148c5f43SAlan Wright 104148c5f43SAlan Wright int 105148c5f43SAlan Wright smbd_nicmon_refresh(void) 106148c5f43SAlan Wright { 107148c5f43SAlan Wright if (smb_nic_init() != SMB_NIC_SUCCESS) 108148c5f43SAlan Wright return (-1); 109148c5f43SAlan Wright 110148c5f43SAlan Wright smbd_nicmon_run_check(); 111148c5f43SAlan Wright return (0); 112148c5f43SAlan Wright } 113148c5f43SAlan Wright 114148c5f43SAlan Wright /* 115148c5f43SAlan Wright * The monitor is enabled unless it is explicitly 116148c5f43SAlan Wright * disabled by setting smbd/nicmon_enable to false. 117148c5f43SAlan Wright * smbd/nicmon_enable is not defined by default. 118148c5f43SAlan Wright */ 119148c5f43SAlan Wright static void 120148c5f43SAlan Wright smbd_nicmon_run_check(void) 121148c5f43SAlan Wright { 122148c5f43SAlan Wright smb_scfhandle_t *hd; 123148c5f43SAlan Wright uint8_t status; 124148c5f43SAlan Wright int rc; 125148c5f43SAlan Wright 126148c5f43SAlan Wright smbd_nicmon_enabled = B_TRUE; 127148c5f43SAlan Wright 128148c5f43SAlan Wright if ((hd = smb_smf_scf_init(SMBD_FMRI_PREFIX)) == NULL) { 129*b819cea2SGordon Ross syslog(LOG_DEBUG, 130148c5f43SAlan Wright "smbd_nicmon: smb_smf_scf_init failed"); 131148c5f43SAlan Wright return; 132148c5f43SAlan Wright } 133148c5f43SAlan Wright 134148c5f43SAlan Wright rc = smb_smf_create_service_pgroup(hd, SMBD_PG_NAME); 135148c5f43SAlan Wright if (rc != SMBD_SMF_OK) { 136148c5f43SAlan Wright smb_smf_scf_fini(hd); 137*b819cea2SGordon Ross syslog(LOG_DEBUG, 138148c5f43SAlan Wright "smbd_nicmon: smb_smf_create_service_pgroup failed"); 139148c5f43SAlan Wright return; 140148c5f43SAlan Wright } 141148c5f43SAlan Wright 142148c5f43SAlan Wright rc = smb_smf_get_boolean_property(hd, SMBD_NICMON_ENABLE, &status); 143148c5f43SAlan Wright if (rc == SMBD_SMF_OK && status == 0) 144148c5f43SAlan Wright smbd_nicmon_enabled = B_FALSE; 145148c5f43SAlan Wright 146148c5f43SAlan Wright smb_smf_scf_fini(hd); 147148c5f43SAlan Wright } 148148c5f43SAlan Wright 149148c5f43SAlan Wright /* 150148c5f43SAlan Wright * Setup routing socket for getting RTM messages. 151148c5f43SAlan Wright */ 152148c5f43SAlan Wright static int 153148c5f43SAlan Wright smbd_nicmon_setup_rtsock(int af) 154148c5f43SAlan Wright { 155148c5f43SAlan Wright int sd; 156148c5f43SAlan Wright int flags; 157148c5f43SAlan Wright 158148c5f43SAlan Wright if ((sd = socket(PF_ROUTE, SOCK_RAW, af)) == -1) { 159*b819cea2SGordon Ross syslog(LOG_ERR, 160148c5f43SAlan Wright "smbd_nicmon: routing socket failed: %d", errno); 161148c5f43SAlan Wright return (-1); 162148c5f43SAlan Wright } 163148c5f43SAlan Wright 164148c5f43SAlan Wright if ((flags = fcntl(sd, F_GETFL, 0)) < 0) { 165*b819cea2SGordon Ross syslog(LOG_ERR, 166148c5f43SAlan Wright "smbd_nicmon: fcntl F_GETFL failed: %d", errno); 167148c5f43SAlan Wright (void) close(sd); 168148c5f43SAlan Wright return (-1); 169148c5f43SAlan Wright } 170148c5f43SAlan Wright 171148c5f43SAlan Wright if ((fcntl(sd, F_SETFL, flags | O_NONBLOCK)) < 0) { 172*b819cea2SGordon Ross syslog(LOG_ERR, 173148c5f43SAlan Wright "smbd_nicmon: fcntl F_SETFL failed: %d", errno); 174148c5f43SAlan Wright (void) close(sd); 175148c5f43SAlan Wright return (-1); 176148c5f43SAlan Wright } 177148c5f43SAlan Wright 178148c5f43SAlan Wright return (sd); 179148c5f43SAlan Wright } 180148c5f43SAlan Wright 181148c5f43SAlan Wright static int 182148c5f43SAlan Wright smbd_nicmon_needscan(int sock) 183148c5f43SAlan Wright { 184148c5f43SAlan Wright static uint32_t throttle; 185148c5f43SAlan Wright struct rt_msghdr *rtm; 186148c5f43SAlan Wright int64_t msg[2048 / 8]; 187148c5f43SAlan Wright int need_if_scan = 0; 188148c5f43SAlan Wright int nbytes; 189148c5f43SAlan Wright 190148c5f43SAlan Wright /* Read as many messages as possible and try to empty the sockets */ 191148c5f43SAlan Wright for (;;) { 192148c5f43SAlan Wright nbytes = read(sock, msg, sizeof (msg)); 193148c5f43SAlan Wright if (nbytes <= 0) 194148c5f43SAlan Wright break; 195148c5f43SAlan Wright 196148c5f43SAlan Wright rtm = (struct rt_msghdr *)msg; 197148c5f43SAlan Wright if (rtm->rtm_version != RTM_VERSION) 198148c5f43SAlan Wright continue; 199148c5f43SAlan Wright 200148c5f43SAlan Wright if (nbytes < rtm->rtm_msglen) { 201148c5f43SAlan Wright if ((throttle % SMBD_NICMON_THROTTLE) == 0) { 202*b819cea2SGordon Ross syslog(LOG_DEBUG, 203148c5f43SAlan Wright "smbd_nicmon: short read: %d of %d", 204148c5f43SAlan Wright nbytes, rtm->rtm_msglen); 205148c5f43SAlan Wright } 206148c5f43SAlan Wright ++throttle; 207148c5f43SAlan Wright continue; 208148c5f43SAlan Wright } 209148c5f43SAlan Wright 210148c5f43SAlan Wright switch (rtm->rtm_type) { 211148c5f43SAlan Wright case RTM_NEWADDR: 212148c5f43SAlan Wright case RTM_DELADDR: 213148c5f43SAlan Wright case RTM_IFINFO: 214148c5f43SAlan Wright need_if_scan = 1; 215148c5f43SAlan Wright break; 216148c5f43SAlan Wright default: 217148c5f43SAlan Wright break; 218148c5f43SAlan Wright } 219148c5f43SAlan Wright } 220148c5f43SAlan Wright 221148c5f43SAlan Wright return (need_if_scan); 222148c5f43SAlan Wright } 223148c5f43SAlan Wright 224148c5f43SAlan Wright /* 225148c5f43SAlan Wright * Create pipe for signal delivery and set up signal handlers. 226148c5f43SAlan Wright */ 227148c5f43SAlan Wright static int 228148c5f43SAlan Wright smbd_nicmon_setup_eventpipe(int *read_pipe, int *write_pipe) 229148c5f43SAlan Wright { 230148c5f43SAlan Wright int fds[2]; 231148c5f43SAlan Wright 232148c5f43SAlan Wright if ((pipe(fds)) < 0) { 233*b819cea2SGordon Ross syslog(LOG_ERR, 234148c5f43SAlan Wright "smbd_nicmon: event pipe failed: %d", errno); 235148c5f43SAlan Wright return (-1); 236148c5f43SAlan Wright } 237148c5f43SAlan Wright 238148c5f43SAlan Wright *read_pipe = fds[0]; 239148c5f43SAlan Wright *write_pipe = fds[1]; 240148c5f43SAlan Wright return (0); 241148c5f43SAlan Wright } 242148c5f43SAlan Wright 243148c5f43SAlan Wright /* 244148c5f43SAlan Wright * Create the global routing socket to monitor changes in NIC interfaces. 245148c5f43SAlan Wright * We are only interested in new inerface addition/deletion and changes 246148c5f43SAlan Wright * in UP/DOWN status. 247148c5f43SAlan Wright * 248148c5f43SAlan Wright * Note: only supports AF_INET routing socket. Need to add AF_INET6 to 249148c5f43SAlan Wright * support IPv6. 250148c5f43SAlan Wright */ 251148c5f43SAlan Wright /*ARGSUSED*/ 252148c5f43SAlan Wright static void * 253148c5f43SAlan Wright smbd_nicmon_daemon(void *arg) 254148c5f43SAlan Wright { 255148c5f43SAlan Wright static uint32_t throttle; 256148c5f43SAlan Wright static int rtsock_v4; 257148c5f43SAlan Wright static int eventpipe_read = -1; 258148c5f43SAlan Wright struct pollfd pollfds[2]; 259148c5f43SAlan Wright int pollfd_num = 2; 260148c5f43SAlan Wright int i, nic_changed; 261148c5f43SAlan Wright int rc; 262148c5f43SAlan Wright 263148c5f43SAlan Wright if ((rtsock_v4 = smbd_nicmon_setup_rtsock(AF_INET)) == -1) 264148c5f43SAlan Wright return (NULL); 265148c5f43SAlan Wright 266148c5f43SAlan Wright rc = smbd_nicmon_setup_eventpipe(&eventpipe_read, &eventpipe_write); 267148c5f43SAlan Wright if (rc != 0) 268148c5f43SAlan Wright return (NULL); 269148c5f43SAlan Wright 270148c5f43SAlan Wright /* 271148c5f43SAlan Wright * Listen for activity on any of the sockets. 272148c5f43SAlan Wright * The delay before checking the rtsock will hopefully 273148c5f43SAlan Wright * smooth things out when there is a lot of activity. 274148c5f43SAlan Wright */ 275148c5f43SAlan Wright for (;;) { 276148c5f43SAlan Wright errno = 0; 277148c5f43SAlan Wright nic_changed = 0; 278148c5f43SAlan Wright pollfds[0].fd = rtsock_v4; 279148c5f43SAlan Wright pollfds[0].events = POLLIN; 280148c5f43SAlan Wright pollfds[1].fd = eventpipe_read; 281148c5f43SAlan Wright pollfds[1].events = POLLIN; 282148c5f43SAlan Wright 283148c5f43SAlan Wright if (poll(pollfds, pollfd_num, -1) < 0) { 284148c5f43SAlan Wright if (errno == EINTR) 285148c5f43SAlan Wright continue; 286148c5f43SAlan Wright if ((throttle % SMBD_NICMON_THROTTLE) == 0) 287*b819cea2SGordon Ross syslog(LOG_DEBUG, 288148c5f43SAlan Wright "smbd_nicmon: poll failed: %d", errno); 289148c5f43SAlan Wright ++throttle; 290148c5f43SAlan Wright break; 291148c5f43SAlan Wright } 292148c5f43SAlan Wright 293148c5f43SAlan Wright for (i = 0; i < pollfd_num; i++) { 294148c5f43SAlan Wright if ((pollfds[i].fd < 0) || 295148c5f43SAlan Wright !(pollfds[i].revents & POLLIN)) 296148c5f43SAlan Wright continue; 297148c5f43SAlan Wright if (pollfds[i].fd == rtsock_v4) { 298148c5f43SAlan Wright (void) sleep(SMBD_NICMON_DEBOUNCE); 299148c5f43SAlan Wright nic_changed = smbd_nicmon_needscan(rtsock_v4); 300148c5f43SAlan Wright } 301148c5f43SAlan Wright if (pollfds[i].fd == eventpipe_read) 302148c5f43SAlan Wright goto done; 303148c5f43SAlan Wright } 304148c5f43SAlan Wright 305148c5f43SAlan Wright /* 306148c5f43SAlan Wright * If the monitor is enabled and something has changed, 307148c5f43SAlan Wright * refresh the registered SMF service. 308148c5f43SAlan Wright */ 309148c5f43SAlan Wright if (smbd_nicmon_enabled && nic_changed && 310148c5f43SAlan Wright smbd_nicmon_caller_fmri) { 311148c5f43SAlan Wright if (smf_refresh_instance(smbd_nicmon_caller_fmri) != 0) 312*b819cea2SGordon Ross syslog(LOG_ERR, 313148c5f43SAlan Wright "smbd_nicmon: %s refresh failed", 314148c5f43SAlan Wright smbd_nicmon_caller_fmri); 315148c5f43SAlan Wright } 316148c5f43SAlan Wright } 317148c5f43SAlan Wright done: 318148c5f43SAlan Wright (void) close(rtsock_v4); 319148c5f43SAlan Wright (void) close(eventpipe_read); 320148c5f43SAlan Wright (void) close(eventpipe_write); 321148c5f43SAlan Wright eventpipe_write = -1; 322148c5f43SAlan Wright return (NULL); 323148c5f43SAlan Wright } 324