/*
* 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
*
*/
#include "defs.h"
#include "tables.h"
#include <fcntl.h>
static void initlog(void);
static void run_timeouts(void);
static void loopback_ra_dequeue(void);
static void check_daemonize(void);
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x1 } };
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2 } };
{ 0xff, 0x2, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x1 } };
{ 0xff, 0x2, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2 } };
static int show_ifs = 0;
int debug = 0;
/*
* Size of routing socket message used by in.ndpd which includes the header,
* space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6)
* plus space for the RTA_IFP (a sockaddr_dl).
*/
sizeof (struct sockaddr_in6) + \
sizeof (struct sockaddr_in6) + \
sizeof (struct sockaddr_in6) + \
sizeof (struct sockaddr_dl)
/*
* These are referenced externally in tables.c in order to fill in the
* dynamic portions of the routing socket message and then to send the message
* itself.
*/
/*
* These sockets are used internally in this file.
*/
static int ndpd_setup_cmd_listener(void);
static void ndpd_cmd_handler(int);
static int ndpd_process_cmd(int, ipadm_ndpd_msg_t *);
static int ndpd_send_error(int, int);
static int ndpd_set_autoconf(const char *, boolean_t);
static int ndpd_create_addrs(const char *, struct sockaddr_in6, int,
static int ndpd_delete_addrs(const char *);
static int phyint_check_ipadm_intfid(struct phyint *);
/*
* Return the current time in milliseconds truncated to
* fit in an integer.
*/
getcurrenttime(void)
{
logperror("getcurrenttime: gettimeofday failed");
exit(1);
}
}
/*
* Output a preformated packet from the packet[] buffer.
*/
static void
{
int cc;
if (cc < 0) {
logperror("sendpacket: sendto");
}
}
}
/*
* If possible, place an ND_OPT_SOURCE_LINKADDR option at `optp'.
* Return the number of bytes placed in the option.
*/
static uint_t
{
/* If this phyint doesn't have a link-layer address, bail */
return (0);
/* roundup to multiple of 8 and make padding zero */
return (optlen);
}
/* Send a Router Solicitation */
static void
{
int packetlen = 0;
rs->nd_rs_code = 0;
/* add options */
sin6);
}
}
/*
* Send a (set of) Router Advertisements and feed them back to ourselves
* for processing. Unless no_prefixes is set all prefixes are included.
* If there are too many prefix options to fit in one packet multiple
* packets will be sent - each containing a subset of the prefix options.
*/
static void
{
int packetlen = 0;
ra->nd_ra_code = 0;
ra->nd_ra_flags_reserved = 0;
if (pi->pi_AdvManagedFlag)
if (pi->pi_AdvOtherConfigFlag)
else
}
/* Feed packet back in for router operation */
return;
}
/* add options */
if (pi->pi_AdvLinkMTU != 0) {
mo->nd_opt_mtu_reserved = 0;
packetlen += sizeof (struct nd_opt_mtu);
pptr += sizeof (struct nd_opt_mtu);
}
if (no_prefixes) {
}
/* Feed packet back in for router operation */
return;
}
if (!adv_pr->adv_pr_AdvOnLinkFlag &&
continue;
}
/*
* If the prefix doesn't fit in packet send
* what we have so far and start with new packet.
*/
print_route_adv("Sending advert "
"(FRAG) to ",
}
/* Feed packet back in for router operation */
}
po->nd_opt_pi_flags_reserved = 0;
if (adv_pr->adv_pr_AdvOnLinkFlag) {
}
if (adv_pr->adv_pr_AdvAutonomousFlag) {
}
/*
* If both Adv*Expiration and Adv*Lifetime are
* set we prefer the former and make the lifetime
* decrement in real time.
*/
if (adv_pr->adv_pr_AdvValidRealTime) {
} else {
}
if (adv_pr->adv_pr_AdvPreferredRealTime) {
} else {
}
po++;
}
}
/* Feed packet back in for router operation */
}
/* Poll support */
/*
* Add fd to the set being polled. Returns 0 if ok; -1 if failed.
*/
int
{
int i;
int new_num;
/* Check if already present */
for (i = 0; i < pollfd_num; i++) {
return (0);
}
/* Check for empty spot already present */
for (i = 0; i < pollfd_num; i++) {
return (0);
}
}
/* Allocate space for 32 more fds and initialize to -1 */
logperror("realloc");
return (-1);
}
for (i = pollfd_num; i < new_num; i++) {
}
return (0);
}
/*
* Remove fd from the set being polled. Returns 0 if ok; -1 if failed.
*/
int
{
int i;
/* Check if already present */
for (i = 0; i < pollfd_num; i++) {
return (0);
}
}
return (-1);
}
/*
* Extract information about the ifname (either a physical interface and
* the ":0" logical interface or just a logical interface).
* If the interface (still) exists in kernel set pr_in_use
* for caller to be able to detect interfaces that are removed.
* Starts sending advertisements/solicitations when new physical interfaces
* are detected.
*/
static void
{
char *cp;
/*
* Interface has disappeared
*/
return;
}
logperror("if_process: ioctl (get interface flags)");
return;
}
/*
* Ignore loopback, point-to-multipoint and VRRP interfaces.
* The IP addresses over VRRP interfaces cannot be auto-configured.
* Point-to-point interfaces always have IFF_MULTICAST set.
*/
return;
}
return;
*cp = '\0';
}
return;
}
/*
* if in.ndpd is restarted, check with ipmgmtd if there is any
* interface id to be configured for this interface.
*/
if (first) {
}
} else {
/*
* if the phyint already exists, synchronize it with
* the kernel state. For a newly created phyint, phyint_create
* calls phyint_init_from_k().
*/
(void) phyint_init_from_k(pi);
}
/* Interface is not yet present */
}
return;
}
/*
* reset state.
*/
}
}
/*
* Check if IFF_ROUTER has been turned off in kernel in which
* case we have to turn off AdvSendAdvertisements.
* The kernel will automatically turn off IFF_ROUTER if
* ip6_forwarding is turned off.
* Note that we do not switch back should IFF_ROUTER be turned on.
*/
if (!first &&
pi->pi_AdvSendAdvertisements = 0;
}
/*
* Send advertisments and solicitation only if the interface is
* present in the kernel.
*/
if (pi->pi_AdvSendAdvertisements) {
} else {
}
}
/*
* Track static kernel prefixes to prevent in.ndpd from clobbering
* them by creating a struct prefix for each prefix detected in the
* kernel.
*/
return;
}
return;
}
}
/* Detect prefixes which are removed */
if (pr->pr_kernel_state != 0)
int i;
"attempts; disabling temporary addresses on %s",
pi->pi_TmpAddrsEnabled = 0;
return;
}
if (!tmptoken_create(pi)) {
return;
}
for (i = 0; i < 16; i++) {
/*
* prefix_create ensures that pr_prefix has all-zero
* bits after prefixlen.
*/
}
return;
}
/*
* We've got a new token. Clearing PR_AUTO causes
* prefix_update_k to bring the interface up and set the
* address.
*/
}
}
/*
* Scan all interfaces to detect changes as well as new and deleted intefaces
* 'first' is set for the initial call only. Do not effect anything.
*/
static void
{
char *buf;
int bufsize;
int numifs;
int n;
if (ifsock < 0) {
if (ifsock < 0) {
logperror("initifs: socket");
return;
}
}
logperror("initifs: ioctl (get interface numbers)");
return;
}
return;
}
/*
* Mark the interfaces so that we can find phyints and prefixes
* which have disappeared from the kernel.
* if_process will set pr_in_use when it finds the interface
* in the kernel.
*/
/*
* Before re-examining the state of the interfaces,
* PI_PRESENT should be cleared from pi_kernel_state.
*/
}
}
logperror("initifs: ioctl (get interface configuration)");
return;
}
/*
* Detect phyints that have been removed from the kernel.
* Since we can't recreate it here (would require ifconfig plumb
* logic) we just terminate use of that phyint.
*/
/*
* If interface (still) exists in kernel, set
* pi_state to indicate that.
*/
}
}
if (show_ifs)
}
/*
* Router advertisement state machine. Used for everything but timer
* events which use advertise_event directly.
*/
void
{
}
if (delay != TIMER_INFINITY) {
/* Make sure the global next event is updated */
}
(int)pi->pi_adv_state);
}
}
/*
* Router advertisement state machine.
* Return the number of milliseconds until next timeout (TIMER_INFINITY
* if never).
* For the ADV_TIMER event the caller passes in the number of milliseconds
* since the last timer event in the 'elapsed' parameter.
*/
{
}
if (!pi->pi_AdvSendAdvertisements)
return (TIMER_INFINITY);
"(no route exchange on interface)\n",
}
return (TIMER_INFINITY);
}
switch (event) {
case ADV_OFF:
return (TIMER_INFINITY);
case START_INIT_ADV:
return (pi->pi_adv_time_left);
pi->pi_adv_time_left = 0;
break; /* send advertisement */
case START_FINAL_ADV:
return (TIMER_INFINITY);
return (pi->pi_adv_time_left);
pi->pi_adv_time_left = 0;
break; /* send advertisement */
case RECEIVED_SOLICIT:
return (TIMER_INFINITY);
if (pi->pi_adv_time_left != 0)
return (pi->pi_adv_time_left);
break;
}
/*
* Send an advertisement (ND_MIN_DELAY_BETWEEN_RAS
* plus random delay) after the previous
* advertisement was sent.
*/
}
break;
case ADV_TIMER:
return (TIMER_INFINITY);
/* Decrease time left */
else
pi->pi_adv_time_left = 0;
/* Increase time since last advertisement was sent */
break;
default:
(int)event);
return (TIMER_INFINITY);
}
if (pi->pi_adv_time_left != 0)
return (pi->pi_adv_time_left);
/* Send advertisement and calculate next time to send */
/* Omit the prefixes */
} else {
}
pi->pi_adv_time_since_sent = 0;
switch (pi->pi_adv_state) {
case SOLICIT_ADV:
/*
* The solicited advertisement has been sent.
* Revert to periodic advertisements.
*/
/* FALLTHRU */
case REG_ADV:
break;
case INIT_ADV:
if (--pi->pi_adv_count > 0) {
} else {
}
break;
case FINAL_ADV:
if (--pi->pi_adv_count > 0) {
} else {
}
break;
}
return (pi->pi_adv_time_left);
else
return (TIMER_INFINITY);
}
/*
* Router solicitation state machine. Used for everything but timer
* events which use solicit_event directly.
*/
void
{
}
if (delay != TIMER_INFINITY) {
/* Make sure the global next event is updated */
}
(int)pi->pi_sol_state);
}
}
static void
daemonize_ndpd(void)
{
/*
* Need to get current timer settings so they can be restored
* after the fork(), as the it_value and it_interval values for
* the ITIMER_REAL timer are reset to 0 in the child process.
*/
"daemonize_ndpd: failed to get itimerval\n");
}
/* Daemonize. */
if (daemon(0, 0) == -1) {
logperror("fork");
exit(1);
}
/*
* Restore timer values, if we were able to save them; if not,
* check and set the right value by calling run_timeouts().
*/
if (timerval) {
logperror("daemonize_ndpd: setitimer");
exit(2);
}
} else {
run_timeouts();
}
}
/*
* Check to see if the time is right to daemonize. The right time is when:
*
* 1. We haven't already daemonized.
* 2. We are not in debug mode.
* 3. All interfaces are marked IFF_NOXMIT.
* 4. All non-router interfaces have their prefixes set up and we're
* done sending router solicitations on those interfaces without
* prefixes.
*/
static void
check_daemonize(void)
{
if (already_daemonized || debug != 0)
return;
break;
}
/*
* If we can't transmit on any of the interfaces there is no reason
* to hold up progress.
*/
return;
}
/* Check all interfaces. If any are still soliciting, just return. */
if (pi->pi_AdvSendAdvertisements ||
continue;
return;
}
}
/*
* Router solicitation state machine.
* Return the number of milliseconds until next timeout (TIMER_INFINITY
* if never).
* For the SOL_TIMER event the caller passes in the number of milliseconds
* since the last timer event in the 'elapsed' parameter.
*/
{
}
if (pi->pi_AdvSendAdvertisements)
return (TIMER_INFINITY);
"(no route exchange on interface)\n",
}
return (TIMER_INFINITY);
}
switch (event) {
case SOLICIT_OFF:
return (TIMER_INFINITY);
case SOLICIT_DONE:
return (TIMER_INFINITY);
case RESTART_INIT_SOLICIT:
/*
* This event allows us to start solicitation over again
* without losing the RA flags. We start solicitation over
* when we are missing an interface prefix for a newly-
* encountered DHCP interface.
*/
return (pi->pi_sol_time_left);
break;
case START_INIT_SOLICIT:
return (pi->pi_sol_time_left);
pi->pi_ra_flags = 0;
break;
case SOL_TIMER:
return (TIMER_INFINITY);
/* Decrease time left */
else
pi->pi_sol_time_left = 0;
break;
default:
(int)event);
return (TIMER_INFINITY);
}
if (pi->pi_sol_time_left != 0)
return (pi->pi_sol_time_left);
/* Send solicitation and calculate next time */
switch (pi->pi_sol_state) {
case INIT_SOLICIT:
if (--pi->pi_sol_count == 0) {
"found on %s; assuming default flags\n",
}
start_dhcp(pi);
}
return (TIMER_INFINITY);
}
return (pi->pi_sol_time_left);
case NO_SOLICIT:
case DONE_SOLICIT:
return (TIMER_INFINITY);
default:
return (pi->pi_sol_time_left);
}
}
/*
* Timer mechanism using relative time (in milliseconds) from the
* previous timer event. Timers exceeding TIMER_INFINITY milliseconds
* will fire after TIMER_INFINITY milliseconds.
*/
static void
timer_init(void)
{
run_timeouts();
}
/*
* Make sure the next SIGALRM occurs delay milliseconds from the current
* time if not earlier.
* Handles getcurrenttime (32 bit integer holding milliseconds) wraparound
* by treating differences greater than 0x80000000 as negative.
*/
void
{
now = getcurrenttime();
}
/* Will this timer occur before the currently scheduled SIGALRM? */
"next in %u ms\n",
}
return;
}
if (delay == 0) {
/* Minimum allowed delay */
delay = 1;
}
}
logperror("timer_schedule: setitimer");
exit(2);
}
}
/*
* Conditional running of timer. If more than 'minimal_time' millseconds
* since the timer routines were last run we run them.
* Used when packets arrive.
*/
static void
{
now = getcurrenttime();
if (elapsed > minimal_time) {
"elapsed %d\n", elapsed);
}
run_timeouts();
}
}
/*
* Timer has fired.
* Determine when the next timer event will occur by asking all
* the timer routines.
* Should not be called from a timer routine but in some cases this is
* done because the code doesn't know that e.g. it was called from
* ifconfig_timer(). In this case the nested run_timeouts will just return but
* the running run_timeouts will ensure to call all the timer functions by
* looping once more.
*/
static void
run_timeouts(void)
{
if (timeout_running) {
return;
}
/* How much time since the last time we were called? */
now = getcurrenttime();
}
}
}
adv_pr = next_adv_pr) {
"(adv pr on %s): %d -> %u ms\n",
}
}
}
}
if (pi->pi_TmpAddrsEnabled) {
}
}
}
/*
* Make sure the timer functions are run at least once
* an hour.
*/
if (next == TIMER_INFINITY)
if (do_retry) {
goto retry;
}
}
/*
* Ensure that signals are processed synchronously with the rest of
* the code by just writing a one character signal number on the pipe.
* The poll loop will pick this up and process the signal event.
*/
static void
{
if (eventpipe_write == -1) {
return;
}
logperror("sig_handler: write");
}
/*
* Pick up a signal "byte" from the pipe and process it.
*/
static void
{
case -1:
logperror("in_signal: read");
exit(1);
/* NOTREACHED */
case 1:
break;
case 0:
exit(1);
/* NOTREACHED */
default:
exit(1);
}
switch (buf) {
case SIGALRM:
now - timer_next);
}
run_timeouts();
break;
case SIGHUP:
/* Re-read config file by exec'ing ourselves */
if (pi->pi_AdvSendAdvertisements)
/*
* Remove all the configured addresses.
* Remove the addrobj names created with ipmgmtd.
* Release the dhcpv6 addresses if any.
* Cleanup the phyints.
*/
}
/*
* Prevent fd leaks. Everything gets re-opened at start-up
* time. 0, 1, and 2 are closed and re-opened as
*/
closefrom(3);
_exit(0177);
/* NOTREACHED */
case SIGUSR1:
break;
case SIGINT:
case SIGTERM:
case SIGQUIT:
if (pi->pi_AdvSendAdvertisements)
}
(void) unlink(NDPD_SNMP_SOCKET);
exit(0);
/* NOTREACHED */
case 255:
/*
* Special "signal" from loopback_ra_enqueue.
* Handle any queued loopback router advertisements.
*/
break;
default:
}
}
/*
* Create pipe for signal delivery and set up signal handlers.
*/
static void
setup_eventpipe(void)
{
logperror("setup_eventpipe: pipe");
exit(1);
}
eventpipe_read = fds[0];
exit(1);
}
}
/*
* Create a routing socket for receiving RTM_IFINFO messages and initialize
* the routing socket message header and as much of the sockaddrs as possible.
*/
static int
setup_rtsock(void)
{
int s;
int ret;
char *cp;
if (s == -1) {
logperror("socket(PF_ROUTE)");
exit(1);
}
if (ret < 0) {
logperror("fcntl(O_NDELAY)");
exit(1);
}
if (poll_add(s) == -1) {
exit(1);
}
/*
* Allocate storage for the routing socket message.
*/
logperror("malloc");
exit(1);
}
/*
* Initialize the routing socket message by zero-filling it and then
* setting the fields where are constant through the lifetime of the
* process.
*/
logperror("getpid");
exit(1);
}
/*
* The RTA_DST sockaddr does not change during the lifetime of the
* process so it can be completely initialized at this time.
*/
/*
* Initialize the constant portion of the RTA_GATEWAY sockaddr.
*/
cp += sizeof (struct sockaddr_in6);
/*
* The RTA_NETMASK sockaddr does not change during the lifetime of the
* process so it can be completely initialized at this time.
*/
cp += sizeof (struct sockaddr_in6);
/*
* Initialize the constant portion of the RTA_IFP sockaddr.
*/
cp += sizeof (struct sockaddr_in6);
return (s);
}
static int
setup_mibsock(void)
{
int sock;
int ret;
int len;
if (sock == -1) {
logperror("setup_mibsock: socket(AF_UNIX)");
exit(1);
}
len = sizeof (struct sockaddr_un);
(void) unlink(NDPD_SNMP_SOCKET);
if (ret < 0) {
logperror("setup_mibsock: bind\n");
exit(1);
}
if (ret < 0) {
logperror("fcntl(O_NONBLOCK)");
exit(1);
}
exit(1);
}
return (sock);
}
/*
* Retrieve one routing socket message. If RTM_IFINFO indicates
* new phyint do a full scan of the interfaces. If RTM_IFINFO
* indicates an existing phyint, only scan that phyint and associated
* prefixes.
*/
static void
{
int n;
int ifscan_index = 0;
int i;
/* Empty the rtsock and coealesce all the work that we have */
while (ifscan_index < 10) {
if (n <= 0) {
/* No more messages */
break;
}
"process_rtsock: version %d not understood\n",
rtm->rtm_version);
return;
}
case RTM_NEWADDR:
case RTM_DELADDR:
/*
* Some logical interface has changed - have to scan
* everything to determine what actually changed.
*/
}
break;
case RTM_IFINFO:
sizeof (msg));
ifscan_index++;
/* Handled below */
break;
default:
/* Not interesting */
break;
}
}
/*
* If we do full scan i.e initifs, we don't need to
* scan a particular interface as we should have
* done that as part of initifs.
*/
if (need_initifs) {
return;
}
if (!need_ifscan)
return;
for (i = 0; i < ifscan_index; i++) {
/*
* A new physical interface. Do a full scan of the
* to catch any new logical interfaces.
*/
return;
}
"%s old flags 0x%llx new flags 0x%x\n",
}
}
/*
* Mark the interfaces so that we can find phyints and prefixes
* which have disappeared from the kernel.
* if_process will set pr_in_use when it finds the
* interface in the kernel.
* Before re-examining the state of the interfaces,
* PI_PRESENT should be cleared from pi_kernel_state.
*/
}
if (ifsock < 0) {
if (ifsock < 0) {
logperror("process_rtsock: socket");
return;
}
}
}
/*
* If interface (still) exists in kernel, set
* pi_state to indicate that.
*/
}
if (show_ifs)
}
}
static void
{
int command;
logperror("process_mibsock: bad command \n");
return;
}
int prefixes;
int routers;
/*
* get number of prefixes
*/
routers = 0;
prefixes = 0;
while (prefix_list != NULL) {
prefixes++;
}
/*
* get number of routers
*/
while (router_list != NULL) {
routers++;
}
/*
* Copy prefix information
*/
while (prefix_list != NULL) {
}
/*
* Copy router information
*/
while (router_list != NULL) {
}
}
}
/*
* Look if the phyint or one of its prefixes have been removed from
* the kernel and take appropriate action.
* Uses pr_in_use and pi{,_kernel}_state.
*/
static void
{
/*
* Detect prefixes which are removed.
* Static prefixes are just removed from our tables.
* Non-static prefixes are recreated i.e. in.ndpd takes precedence
* over manually removing prefixes via ifconfig.
*/
/* Clear everything except PR_STATIC */
/*
* Ensure that there are no future attempts to
* run prefix_update_k since the phyint is gone.
*/
}
}
}
/*
* Detect phyints that have been removed from the kernel, and tear
* down any prefixes we created that are associated with that phyint.
* (NOTE: IPMP depends on in.ndpd tearing down these prefixes so an
* administrator can easily place an IP interface with ADDRCONF'd
* addresses into an IPMP group.)
*/
}
/*
* Clear state so that should the phyint reappear we will
* start with initial advertisements or solicitations.
*/
}
}
/*
* Queuing mechanism for router advertisements that are sent by in.ndpd
* and that also need to be processed by in.ndpd.
* Uses "signal number" 255 to indicate to the main poll loop
* that there is something to dequeue and send to incomining_ra().
*/
struct raq {
int raq_packetlen;
};
/*
* Allocate a struct raq and memory for the packet.
* Send signal 255 to have poll dequeue.
*/
static void
{
if (no_loopback)
return;
return;
}
return;
}
/* Tail insert */
/* Signal for poll loop */
sig_handler(255);
}
/*
* Dequeue and process all queued advertisements.
*/
static void
loopback_ra_dequeue(void)
{
}
}
}
static void
{
"usage: %s [ -adt ] [-f <config file>]\n", cmd);
}
int
{
int i;
int c;
(void) umask(0022);
switch (c) {
case 'a':
/*
* The StatelessAddrConf variable in ndpd.conf, if
* present, will override this setting.
*/
break;
case 'd':
break;
case 'D':
if (i == 0) {
(char *)optarg);
exit(1);
}
debug |= i;
break;
case 'n':
no_loopback = 1;
break;
case 'I':
show_ifs = 1;
break;
case 't':
break;
case 'f':
config_file = (char *)optarg;
break;
case '?':
exit(1);
}
}
exit(2);
if (show_ifs)
if (debug == 0)
initlog();
rtsock = setup_rtsock();
mibsock = setup_mibsock();
timer_init();
for (;;) {
continue;
logperror("main: poll");
exit(1);
}
for (i = 0; i < pollfd_num; i++) {
continue;
break;
}
break;
}
break;
}
break;
}
/*
* Run timer routine to advance clock if more than
* half a second since the clock was advanced.
* This limits CPU usage under severe packet
* arrival rates but it creates a slight inaccuracy
* in the timer mechanism.
*/
conditional_run_timeouts(500U);
break;
}
}
}
}
/* NOTREACHED */
return (0);
}
/*
* LOGGER
*/
static void
initlog(void)
{
}
static void
{
}
/* PRINTFLIKE2 */
void
{
if (logging) {
} else {
}
}
void
{
if (logging) {
} else {
}
}
void
{
if (logging) {
} else {
}
}
void
{
if (logging) {
} else {
}
}
static int
ndpd_setup_cmd_listener(void)
{
int sock;
int ret;
if (sock < 0) {
logperror("socket");
exit(1);
}
if (ret < 0) {
logperror("bind");
exit(1);
}
logperror("listen");
exit(1);
}
"polling set\n");
exit(1);
}
return (sock);
}
/*
* Commands received over the command socket come here
*/
static void
{
int newfd;
int retval;
if (newfd < 0) {
logperror("accept");
return;
}
if (retval != 0)
logperror("Could not read ndpd command");
if (retval != 0) {
}
}
/*
* Process the commands received from the cmd listener socket.
*/
static int
{
int err;
if (!ipadm_check_auth()) {
return (EPERM);
}
case IPADM_DISABLE_AUTOCONF:
break;
case IPADM_ENABLE_AUTOCONF:
break;
case IPADM_CREATE_ADDRS:
break;
case IPADM_DELETE_ADDRS:
break;
default:
break;
}
return (err);
}
static int
{
}
/*
* given physical interface.
* This is provided to support the legacy method of configuring IPv6
* addresses. i.e. `ifconfig bge0 inet6 plumb` will plumb the interface
* and start stateless and stateful autoconfiguration. If this function is
* not called with enable=_B_FALSE, no autoconfiguration will be done until
* ndpd_create_addrs() is called with an Interface ID.
*/
static int
{
/*
* If the physical interface was plumbed but no
* addresses were configured yet, phyint will not exist.
*/
"interface %s", ifname);
return (ENOMEM);
}
}
}
return (0);
}
/*
* Create auto-configured addresses on the given interface using
* the given token as the interface id during the next Router Advertisement.
* Currently, only one token per interface is supported.
*/
static int
{
int err;
/*
* If the physical interface was plumbed but no
* addresses were configured yet, phyint will not exist.
*/
"for interface %s", ifname);
return (ENOMEM);
}
} else if (pi->pi_autoconf) {
return (EEXIST);
}
if (intfidlen == 0) {
if (ifsock < 0) {
if (ifsock < 0) {
logperror("ndpd_create_addrs: socket");
return (err);
}
}
logperror("SIOCGLIFTOKEN");
return (err);
}
} else {
}
sizeof (pi->pi_ipadm_aobjname));
/* We can allow autoconfiguration now. */
/* Restart the solicitations. */
return (0);
}
/*
* This function deletes all addresses on the given interface
* with the given Interface ID.
*/
static int
{
int err;
return (ENXIO);
}
return (EINVAL);
}
if (ifsock < 0) {
if (ifsock < 0) {
logperror("ndpd_create_addrs: socket");
return (err);
}
}
/* Remove the prefixes for this phyint if they exist */
continue;
}
/*
* Delete all the prefixes for the auto-configured
* addresses as well as the DHCPv6 addresses.
*/
logperror("SIOCGLIFFLAGS");
return (err);
}
}
}
/*
* If we had started dhcpagent, we need to release the leases
* if any are required.
*/
if (pi->pi_stateful) {
logperror("SIOCGLIFFLAGS");
return (err);
}
}
/*
* Reset the Interface ID on this phyint and stop autoconfigurations
* until a new interface ID is provided.
*/
pi->pi_token_length = 0;
/* Reset the stateless and stateful settings to default. */
}
return (0);
}
void
{
/*
* If StatelessAddrConf and StatelessAddrConf are set in
* settings. If so, log a warning.
*/
if ((pi->pi_StatelessAddrConf !=
(pi->pi_StatefulAddrConf !=
"Overriding the StatelessAddrConf or StatefulAddrConf "
"settings in ndpd.conf with the new values for "
}
}
/*
* If ipadm was used to start autoconfiguration and in.ndpd was restarted
* for some reason, in.ndpd has to resume autoconfiguration when it comes up.
* In this function, it scans the ipadm_addr_info() output to find a link-local
* on this interface with address type "addrconf" and extracts the interface id.
* It also stores the addrobj name to be used later when new addresses are
* created for the prefixes advertised by the router.
* If autoconfiguration was never started on this interface before in.ndpd
* was killed, then in.ndpd should refrain from configuring prefixes, even if
* there is a valid link-local on this interface, created by ipadm (identified
* if there is a valid addrobj name).
*/
static int
{
return (-1);
}
if (status != IPADM_SUCCESS) {
return (-1);
}
continue;
sizeof (pi->pi_ipadm_aobjname));
break;
}
/*
* If IFF_NOLINKLOCAL is set, then the link-local
* was created using ipadm. Do not autoconfigure until
* ipadm is explicitly used for autoconfiguration.
*/
/* The interface was created using ipadm. */
}
}
if (!pi->pi_autoconf) {
pi->pi_token_length = 0;
}
return (0);
}