xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/ncaconfd/ncaconfd.c (revision b819cea2f73f98c5662230cc9affc8cc84f77fcf)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/tihdr.h>
32 #include <stropts.h>
33 #include <fcntl.h>
34 #include <syslog.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <libintl.h>
41 #include <locale.h>
42 #include <unistd.h>
43 #include <sys/varargs.h>
44 
45 #include <netinet/in.h>
46 #include <sys/ethernet.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/sysmacros.h>
50 #include <net/if.h>
51 #include <inet/mib2.h>
52 #include <inet/ip.h>
53 #include <net/route.h>
54 #include <arpa/inet.h>
55 #include "ncaconf.h"
56 
57 /* NCA does not support IPv6... */
58 #ifndef	NCA_MOD_NAME
59 #define	NCA_MOD_NAME	"nca"
60 #endif
61 
62 #ifndef	ARP_MOD_NAME
63 #define	ARP_MOD_NAME	"arp"
64 #endif
65 
66 #define	IF_SEPARATOR	':'
67 
68 #define	ping_prog	"/usr/sbin/ping"
69 
70 /* Structure to hold info about each network interface. */
71 typedef struct nif_s {
72 	char		name[LIFNAMSIZ+1];
73 	struct in_addr	local_addr;
74 	struct in_addr	router_addr;
75 	uchar_t		router_ether_addr[ETHERADDRL];
76 } nif_t;
77 
78 typedef struct mib_item_s {
79 	struct mib_item_s	*next_item;
80 	int			group;
81 	int			mib_id;
82 	int			length;
83 	char			*valp;
84 } mib_item_t;
85 
86 /* The network interface array. */
87 static nif_t *nif_list;
88 /* Number of network interface to process. */
89 static int num_nif;
90 
91 /* Interface request to IP. */
92 static struct lifreq lifr;
93 
94 /* True if syslog is to be used. */
95 static boolean_t logging;
96 /* True if additional debugging messages are printed. */
97 static boolean_t debug;
98 
99 /* File descriptor to the routing socket. */
100 static int rt_fd;
101 
102 static void logperror(char *);
103 static void logwarn(char *, ...);
104 static void logdebug(char *, ...);
105 static int ip_domux2fd(int *, int *);
106 static void ip_plink(int, int);
107 static int find_nca_pos(int);
108 static int nca_set_nif(int, struct in_addr, uchar_t *);
109 static void nca_setup(boolean_t *);
110 static int get_if_ip_addr(void);
111 static mib_item_t *mibget(int);
112 static int ire_process(mib2_ipRouteEntry_t *, size_t, boolean_t *);
113 static int arp_process(mib2_ipNetToMediaEntry_t *, size_t, boolean_t *);
114 static int get_router_ip_addr(mib_item_t *, boolean_t *);
115 static int get_router_ether_addr(mib_item_t *, boolean_t *);
116 static int get_if_info(boolean_t *);
117 static void daemon_init(void);
118 static void daemon_work(void);
119 static void ping_them(void);
120 
121 /*
122  * Print out system error messages, either to syslog or stderr.  Note that
123  * syslog() should print out system error messages in the correct language
124  * used.  There is no need to use gettext().
125  */
126 static void
127 logperror(char *str)
128 {
129 	if (logging) {
130 		syslog(LOG_ERR, "%s: %m\n", str);
131 	} else {
132 		(void) fprintf(stderr, "ncaconfd: %s: %s\n", str,
133 		    strerror(errno));
134 	}
135 }
136 
137 /*
138  * Print out warning messages.  The caller should use gettext() to have
139  * the message printed out in the correct language.
140  */
141 /*PRINTFLIKE1*/
142 static void
143 logwarn(char *fmt, ...)
144 {
145 	va_list ap;
146 
147 	va_start(ap, fmt);
148 	if (logging) {
149 		vsyslog(LOG_WARNING, fmt, ap);
150 	} else {
151 		(void) fprintf(stderr, "ncaconfd: ");
152 		(void) vfprintf(stderr, fmt, ap);
153 	}
154 	va_end(ap);
155 }
156 
157 /*
158  * Print out debugging info.  Note that syslogd(1M) should be configured to
159  * take ordinary debug info for it to get this kind of info.
160  */
161 /*PRINTFLIKE1*/
162 static void
163 logdebug(char *fmt, ...)
164 {
165 	va_list ap;
166 
167 	va_start(ap, fmt);
168 	if (logging) {
169 		vsyslog(LOG_WARNING, fmt, ap);
170 	} else {
171 		(void) fprintf(stderr, "ncaconfd: ");
172 		(void) vfprintf(stderr, fmt, ap);
173 	}
174 	va_end(ap);
175 }
176 
177 /*
178  * Helper function for nca_setup().  It gets a fd to the lower IP
179  * stream and I_PUNLINK's the lower stream.  It also initializes the
180  * global variable lifr.
181  *
182  * Param:
183  *	int *udp_fd: (referenced) fd to /dev/udp (upper IP stream).
184  *	int *fd: (referenced) fd to the lower IP stream.
185  *
186  * Return:
187  *	-1 if operation fails, 0 otherwise.
188  */
189 static int
190 ip_domux2fd(int *udp_fd, int *fd)
191 {
192 	int ip_fd;
193 
194 	if ((ip_fd = open(IP_DEV_NAME, O_RDWR)) < 0) {
195 		logperror("Cannot open IP");
196 		return (-1);
197 	}
198 	if ((*udp_fd = open(UDP_DEV_NAME, O_RDWR)) < 0) {
199 		logperror("Cannot open UDP");
200 		(void) close(ip_fd);
201 		return (-1);
202 	}
203 	if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
204 		logperror("ioctl(SIOCGLIFMUXID) failed");
205 		(void) close(ip_fd);
206 		return (-1);
207 	}
208 	if (debug) {
209 		logdebug("ARP_muxid %d IP_muxid %d\n", lifr.lifr_arp_muxid,
210 		    lifr.lifr_ip_muxid);
211 	}
212 	if ((*fd = ioctl(*udp_fd, _I_MUXID2FD, lifr.lifr_ip_muxid)) < 0) {
213 		logperror("ioctl(_I_MUXID2FD) failed");
214 		(void) close(ip_fd);
215 		(void) close(*udp_fd);
216 		return (-1);
217 	}
218 	(void) close(ip_fd);
219 	return (0);
220 }
221 
222 /*
223  * Helper function for nca_setup().  It I_PLINK's back the upper and
224  * lower IP streams.  Note that this function must be called after
225  * ip_domux2fd().  In ip_domux2fd(), the global variable lifr is initialized
226  * and ip_plink() needs information in lifr.  So ip_domux2fd() and ip_plink()
227  * must be called in pairs.
228  *
229  * Param:
230  *	int udp_fd: fd to /dev/udp (upper IP stream).
231  *	int fd: fd to the lower IP stream.
232  */
233 static void
234 ip_plink(int udp_fd, int fd)
235 {
236 	int mux_id;
237 
238 	if ((mux_id = ioctl(udp_fd, I_PLINK, fd)) < 0) {
239 		logperror("ioctl(I_PLINK) failed");
240 		return;
241 	}
242 	if (debug > 0) {
243 		logdebug("New IP_muxid %d\n", mux_id);
244 	}
245 	lifr.lifr_ip_muxid = mux_id;
246 	if (ioctl(udp_fd, SIOCSLIFMUXID, (caddr_t)&lifr) < 0) {
247 		logperror("ioctl(SIOCSLIFMUXID) failed");
248 	}
249 }
250 
251 #define	FOUND_NCA	-1
252 #define	FOUND_NONE	-2
253 /*
254  * Find the proper position to insert NCA, which is just below IP.
255  *
256  * Param:
257  *	int fd: fd to the lower IP stream.
258  *
259  * Return:
260  *	If positive, it is the position to insert NCA.
261  *	FOUND_NCA: found NCA!  So skip this one for plumbing.  But we
262  *		still keep it in the interface list.
263  *	FOUND_NONE: could not find IP or encounter other errors.  Remove
264  *		this interface from the	list.
265  */
266 static int
267 find_nca_pos(int fd)
268 {
269 	int num_mods;
270 	int i, pos;
271 	struct str_list strlist;
272 	boolean_t found_ip = B_FALSE;
273 	boolean_t found_nca = B_FALSE;
274 
275 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
276 		logperror("ioctl(I_LIST) failed");
277 		return (FOUND_NONE);
278 	} else {
279 		strlist.sl_nmods = num_mods;
280 		strlist.sl_modlist = calloc(num_mods,
281 		    sizeof (struct str_mlist));
282 		if (strlist.sl_modlist == NULL) {
283 			logperror("cannot malloc");
284 			return (FOUND_NONE);
285 		} else {
286 			if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
287 				logperror("ioctl(I_LIST) failed");
288 			} else {
289 				for (i = 0; i < strlist.sl_nmods; i++) {
290 					if (strcmp(IP_MOD_NAME,
291 					    strlist.sl_modlist[i].l_name)
292 					    == 0) {
293 						found_ip = B_TRUE;
294 						/*
295 						 * NCA should be just below
296 						 * IP.
297 						 */
298 						pos = i + 1;
299 					} else if (strncmp(NCA_MOD_NAME,
300 					    strlist.sl_modlist[i].l_name,
301 					    strlen(NCA_MOD_NAME)) == 0) {
302 						found_nca = B_TRUE;
303 					}
304 				}
305 			}
306 			free(strlist.sl_modlist);
307 		}
308 	}
309 	if (found_nca) {
310 		return (FOUND_NCA);
311 	} else if (found_ip) {
312 		if (debug) {
313 			logdebug("NCA is at position %d in the stream.\n", pos);
314 		}
315 		return (pos);
316 	} else {
317 		if (debug) {
318 			logdebug("Cannot find IP??\n");
319 		}
320 		return (FOUND_NONE);
321 	}
322 }
323 
324 /*
325  * To set the local IP address and default router ethernet address.
326  *
327  * Param:
328  *	int fd: the fd to the lower IP stream.
329  *	struct in_addr local_addr: the IP address for this interface.
330  *	uchar_t *ether_addr: the ethernet address of the default router for
331  *		for this interface.
332  *
333  * Return:
334  *	-1 if the system does not support this NCA ioctl(), 0 otherwise.
335  */
336 static int
337 nca_set_nif(int fd, struct in_addr local_addr, uchar_t *ether_addr)
338 {
339 	struct nca_set_ioctl nca_ioctl;
340 	struct strioctl strioc;
341 	int len;
342 	uchar_t *dst;
343 
344 	strioc.ic_cmd = NCA_SET_IF;
345 	strioc.ic_timout = INFTIM;
346 	strioc.ic_len = sizeof (nca_ioctl);
347 	strioc.ic_dp = (char *)&nca_ioctl;
348 
349 	nca_ioctl.local_addr = local_addr.s_addr;
350 	dst = nca_ioctl.router_ether_addr;
351 	for (len = ETHERADDRL; len > 0; len--)
352 		*dst++ = *ether_addr++;
353 	nca_ioctl.action = ADD_DEF_ROUTE;
354 
355 	if (ioctl(fd, I_STR, &strioc) < 0) {
356 		logperror("ioctl(NCA_SET_IF) failed");
357 		if (errno == EINVAL)
358 			return (-1);
359 	}
360 	return (0);
361 }
362 
363 /*
364  * To setup the NCA stream.  First insert NCA into the proper position.
365  * Then tell NCA the local IP address and default router by using the
366  * NCA_SET_IF ioctl.
367  *
368  * Param:
369  *	boolean_t *active: (referenced) B_TRUE if NCA is setup to do active
370  *		connection.  If NCA does not support active connection,
371  *		in return, active will be set to B_FALSE.
372  */
373 static void
374 nca_setup(boolean_t *active)
375 {
376 	int i;
377 	int udp_fd;
378 	int fd;
379 	struct strmodconf mod;
380 	/* 128 is enough because interface name can only be LIFNAMSIZ long. */
381 	char err_buf[128];
382 
383 	mod.mod_name = NCA_MOD_NAME;
384 	lifr.lifr_addr.ss_family = AF_INET;
385 	for (i = 0; i < num_nif; i++) {
386 		if (debug) {
387 			logdebug("Plumbing NCA for %s\n", nif_list[i].name);
388 		}
389 		/* This interface does not exist according to IP. */
390 		if (nif_list[i].local_addr.s_addr == 0) {
391 			continue;
392 		}
393 		(void) strlcpy(lifr.lifr_name, nif_list[i].name,
394 		    sizeof (lifr.lifr_name));
395 
396 		if (ip_domux2fd(&udp_fd, &fd) < 0) {
397 			continue;
398 		}
399 		if (ioctl(udp_fd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
400 			(void) snprintf(err_buf, sizeof (err_buf),
401 			    "ioctl(I_PUNLINK) for %s failed", nif_list[i].name);
402 			logperror(err_buf);
403 			(void) close(udp_fd);
404 			(void) close(fd);
405 			continue;
406 		}
407 		if ((mod.pos = find_nca_pos(fd)) < 0) {
408 			if (mod.pos == FOUND_NCA) {
409 				if (debug) {
410 					logdebug("Find NCA in the %s"
411 					    " stream\n", nif_list[i].name);
412 				}
413 				/* Just skip plumbing NCA. */
414 				goto set_nif;
415 			}
416 			if (debug) {
417 				logdebug("Cannot find pos for %s\n",
418 				    nif_list[i].name);
419 			}
420 			goto clean_up;
421 		}
422 		if (ioctl(fd, _I_INSERT, (caddr_t)&mod) < 0) {
423 			(void) snprintf(err_buf, sizeof (err_buf),
424 			    "ioctl(_I_INSERT) for %s failed", nif_list[i].name);
425 			logperror(err_buf);
426 			goto clean_up;
427 		}
428 
429 		/*
430 		 * Only do the following if NCA is also used to make
431 		 * outgoing connections, and all necessary info is
432 		 * there.
433 		 */
434 set_nif:
435 		if (*active && nif_list[i].router_addr.s_addr != 0) {
436 			if (nca_set_nif(fd, nif_list[i].local_addr,
437 			    nif_list[i].router_ether_addr) < 0) {
438 				/*
439 				 * The system does not support this ioctl()!
440 				 * Skip all active stack processing but
441 				 * continue to plumb NCA.
442 				 */
443 				logwarn("NCA does not support active stack!");
444 				*active = B_FALSE;
445 			}
446 		}
447 clean_up:
448 		ip_plink(udp_fd, fd);
449 		(void) close(udp_fd);
450 		(void) close(fd);
451 	}
452 }
453 
454 /*
455  * To get IP address of network interface from IP.
456  */
457 static int
458 get_if_ip_addr(void)
459 {
460 	int sock;
461 	struct lifnum lifn;
462 	struct lifconf lifc;
463 	struct lifreq *lifr;
464 	struct sockaddr_in *sin;
465 	char *buf;
466 	int num_lifr;
467 	int i, j;
468 
469 	/* NCA only supports IPv4... */
470 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
471 		logperror(gettext("Cannot open socket"));
472 		return (-1);
473 	}
474 	lifn.lifn_family = AF_UNSPEC;
475 	lifn.lifn_flags = 0;
476 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
477 		logperror(gettext("ioctl(SIOCGLIFNUM) failed"));
478 		(void) close(sock);
479 		return (-1);
480 	}
481 	buf = (char *)calloc(lifn.lifn_count, sizeof (struct lifreq));
482 	if (buf == NULL) {
483 		logperror(gettext("calloc() failed"));
484 		(void) close(sock);
485 		return (-1);
486 	}
487 
488 	lifc.lifc_family = AF_UNSPEC;
489 	lifc.lifc_flags = 0;
490 	lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
491 	lifc.lifc_buf = buf;
492 
493 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
494 		/*
495 		 * NCA is set up after all the interfaces have been
496 		 * plumbed.  So normally we should not get any error.
497 		 * Just abort if we encounter an error.
498 		 */
499 		logperror(gettext("ioctl(SIOCGLIFCONF) failed"));
500 		free(buf);
501 		(void) close(sock);
502 		return (-1);
503 	}
504 	num_lifr = lifc.lifc_len / sizeof (struct lifreq);
505 	/* Find the interface and copy the local IP address. */
506 	for (i = 0; i < num_nif; i++) {
507 		lifr = (struct lifreq *)lifc.lifc_req;
508 		for (j = num_lifr; j > 0; j--, lifr++) {
509 			/* Again, NCA only supports IPv4. */
510 			if (lifr->lifr_addr.ss_family != AF_INET)
511 				continue;
512 			if (strncmp(nif_list[i].name, lifr->lifr_name,
513 			    strlen(nif_list[i].name)) == 0) {
514 				sin = (struct sockaddr_in *)&lifr->lifr_addr;
515 				nif_list[i].local_addr = sin->sin_addr;
516 				if (debug) {
517 					logdebug("IP address of %s: %s\n",
518 					    nif_list[i].name,
519 					    inet_ntoa(sin->sin_addr));
520 				}
521 				break;
522 			}
523 		}
524 		if (j == 0) {
525 			/*
526 			 * The interface does not exist according to IP!
527 			 * Log a warning and go on.
528 			 */
529 			logwarn(gettext("Network interface %s"
530 			    " does not exist!\n"), nif_list[i].name);
531 			/*
532 			 * Set local_addr to 0 so that nca_setup() will
533 			 * not do anything for this interface.
534 			 */
535 			nif_list[i].local_addr.s_addr = 0;
536 		}
537 	}
538 	free(buf);
539 	(void) close(sock);
540 	return (0);
541 }
542 
543 /*
544  * Get MIB2 info from IP.
545  *
546  * Param:
547  *	int sd: descriptor to IP to send down mib request.
548  */
549 static mib_item_t *
550 mibget(int sd)
551 {
552 	char			buf[1024];
553 	int			flags;
554 	int			i, j, getcode;
555 	struct strbuf		ctlbuf, databuf;
556 	/* LINTED */
557 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
558 	/* LINTED */
559 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
560 	/* LINTED */
561 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
562 	struct opthdr		*req;
563 	mib_item_t		*first_item = (mib_item_t *)0;
564 	mib_item_t		*last_item  = (mib_item_t *)0;
565 	mib_item_t		*temp;
566 
567 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
568 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
569 	tor->OPT_length = sizeof (struct opthdr);
570 	tor->MGMT_flags = T_CURRENT;
571 	req = (struct opthdr *)&tor[1];
572 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
573 	req->name  = 0;
574 	req->len   = 0;
575 
576 	ctlbuf.buf = buf;
577 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
578 	flags = 0;
579 	if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
580 		logperror("mibget: putmsg(ctl) failed");
581 		goto error_exit;
582 	}
583 
584 	/*
585 	 * Each reply consists of a ctl part for one fixed structure
586 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
587 	 * containing an opthdr structure.  level/name identify the entry,
588 	 * len is the size of the data part of the message.
589 	 */
590 	req = (struct opthdr *)&toa[1];
591 	ctlbuf.maxlen = sizeof (buf);
592 	j = 1;
593 	for (;;) {
594 		flags = 0;
595 		getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
596 		if (getcode == -1) {
597 			logperror("mibget getmsg(ctl) failed");
598 			if (debug) {
599 				logdebug("#   level   name    len\n");
600 				i = 0;
601 				for (last_item = first_item; last_item;
602 					last_item = last_item->next_item)
603 					(void) printf("%d  %4d   %5d   %d\n",
604 					    ++i,
605 					    last_item->group,
606 					    last_item->mib_id,
607 					    last_item->length);
608 			}
609 			goto error_exit;
610 		}
611 		if (getcode == 0 &&
612 		    ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
613 		    toa->PRIM_type == T_OPTMGMT_ACK &&
614 		    toa->MGMT_flags == T_SUCCESS &&
615 		    req->len == 0) {
616 			if (debug) {
617 				logdebug("mibget getmsg() %d returned "
618 				    "EOD (level %ld, name %ld)\n",
619 				    j, req->level, req->name);
620 			}
621 			return (first_item);		/* this is EOD msg */
622 		}
623 
624 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
625 		    tea->PRIM_type == T_ERROR_ACK) {
626 			logwarn("mibget %d gives T_ERROR_ACK: TLI_error ="
627 			    " 0x%lx, UNIX_error = 0x%lx\n",
628 			    j, tea->TLI_error, tea->UNIX_error);
629 			errno = (tea->TLI_error == TSYSERR) ?
630 			    tea->UNIX_error : EPROTO;
631 			goto error_exit;
632 		}
633 
634 		if (getcode != MOREDATA ||
635 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
636 		    toa->PRIM_type != T_OPTMGMT_ACK ||
637 		    toa->MGMT_flags != T_SUCCESS) {
638 			logwarn("mibget getmsg(ctl) %d returned %d, "
639 			    "ctlbuf.len = %d, PRIM_type = %ld\n",
640 			    j, getcode, ctlbuf.len, toa->PRIM_type);
641 			if (toa->PRIM_type == T_OPTMGMT_ACK) {
642 				logwarn("T_OPTMGMT_ACK: "
643 				    "MGMT_flags = 0x%lx, req->len = %ld\n",
644 				    toa->MGMT_flags, req->len);
645 			}
646 			errno = ENOMSG;
647 			goto error_exit;
648 		}
649 
650 		temp = (mib_item_t *)malloc(sizeof (mib_item_t));
651 		if (!temp) {
652 			logperror("mibget malloc failed");
653 			goto error_exit;
654 		}
655 		if (last_item)
656 			last_item->next_item = temp;
657 		else
658 			first_item = temp;
659 		last_item = temp;
660 		last_item->next_item = (mib_item_t *)0;
661 		last_item->group = req->level;
662 		last_item->mib_id = req->name;
663 		last_item->length = req->len;
664 		last_item->valp = malloc((int)req->len);
665 
666 		databuf.maxlen = last_item->length;
667 		databuf.buf    = last_item->valp;
668 		databuf.len    = 0;
669 		flags = 0;
670 		getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags);
671 		if (getcode == -1) {
672 			logperror("mibget getmsg(data) failed");
673 			goto error_exit;
674 		} else if (getcode != 0) {
675 			logwarn("mibget getmsg(data) returned %d, "
676 			    "databuf.maxlen = %d, databuf.len = %d\n",
677 			    getcode, databuf.maxlen, databuf.len);
678 			goto error_exit;
679 		}
680 		j++;
681 	}
682 
683 error_exit:;
684 	while (first_item) {
685 		last_item = first_item;
686 		first_item = first_item->next_item;
687 		free(last_item);
688 	}
689 	return (first_item);
690 }
691 
692 /*
693  * Examine the IPv4 routing table for default routers.  For each interface,
694  * find its default router.
695  *
696  * Param:
697  *	mib2_ipRouteEntry_t *buf: the mib info buffer.
698  *	size_t len: length of buffer.
699  *	boolean_t *changed (referenced): set to B_TRUE if there is a change
700  *		in router info.
701  *
702  * Return:
703  *	number of default router found.
704  */
705 static int
706 ire_process(mib2_ipRouteEntry_t *buf, size_t len, boolean_t *changed)
707 {
708 	mib2_ipRouteEntry_t 	*rp;
709 	mib2_ipRouteEntry_t 	*rp1;
710 	mib2_ipRouteEntry_t 	*rp2;
711 	struct	in_addr		nexthop_v4;
712 	mib2_ipRouteEntry_t	*endp;
713 	char			ifname[LIFNAMSIZ + 1];
714 	char			*cp;
715 	int			i;
716 	int			ifname_len;
717 	boolean_t		found;
718 	int			num_found = 0;
719 
720 	if (len == 0)
721 		return (0);
722 	endp = buf + (len / sizeof (mib2_ipRouteEntry_t));
723 
724 	for (i = 0; i < num_nif; i++) {
725 		/*
726 		 * Loop thru the routing table entries. Process any
727 		 * IRE_DEFAULT ire.  Ignore the others.  For each such
728 		 * ire, get the nexthop gateway address.
729 		 */
730 		found = B_FALSE;
731 		for (rp = buf; rp < endp; rp++) {
732 			/*
733 			 * NCA is only interested in default routes associated
734 			 * with an interface.
735 			 */
736 			if (!(rp->ipRouteInfo.re_ire_type & IRE_DEFAULT)) {
737 				continue;
738 			}
739 			/*  Get the nexthop address. */
740 			nexthop_v4.s_addr = rp->ipRouteNextHop;
741 
742 			/*
743 			 * Right now, not all IREs have the interface name
744 			 * it is associated with.
745 			 */
746 			if (rp->ipRouteIfIndex.o_length == 0) {
747 				/*
748 				 * We don't have the outgoing interface in
749 				 * this case.  Get the nexthop address. Then
750 				 * determine the outgoing interface, by
751 				 * examining all interface IREs, and
752 				 * picking the match.
753 				 */
754 				for (rp1 = buf; rp1 < endp; rp1++) {
755 
756 				if (!(rp1->ipRouteInfo.re_ire_type &
757 				    IRE_INTERFACE)) {
758 					continue;
759 				}
760 
761 				/*
762 				 * Determine the interface IRE that
763 				 * matches the nexthop. i.e.
764 				 * (IRE addr & IRE mask) ==
765 				 * (nexthop & IRE mask)
766 				 */
767 				if ((rp1->ipRouteDest & rp1->ipRouteMask) ==
768 				    (nexthop_v4.s_addr & rp1->ipRouteMask)) {
769 					/*
770 					 * We found the interface to go to
771 					 * the default router.  Check the
772 					 * interface name.
773 					 */
774 					/* Can this be possible?? */
775 					if (rp1->ipRouteIfIndex.o_length == 0)
776 						continue;
777 					rp2 = rp1;
778 					break;
779 				}
780 
781 				} /* End inner for loop. */
782 			} else {
783 				rp2 = rp;
784 			}
785 
786 			ifname_len = MIN(rp2->ipRouteIfIndex.o_length,
787 			    sizeof (ifname) - 1);
788 			(void) memcpy(ifname, rp2->ipRouteIfIndex.o_bytes,
789 			    ifname_len);
790 			ifname[ifname_len] = '\0';
791 			if (ifname[0] == '\0')
792 				continue;
793 			cp = strchr(ifname, IF_SEPARATOR);
794 			if (cp != NULL)
795 				*cp = '\0';
796 
797 			/* We are sure both are NULL terminated. */
798 			if (strcmp(nif_list[i].name, ifname) == 0) {
799 				/* No change, do not do anything. */
800 				if (nexthop_v4.s_addr ==
801 				    nif_list[i].router_addr.s_addr) {
802 					found = B_TRUE;
803 					break;
804 				}
805 				nif_list[i].router_addr.s_addr =
806 				    nexthop_v4.s_addr;
807 				if (debug) {
808 					logdebug("Get default"
809 					    " router for %s: %s\n", ifname,
810 					    inet_ntoa(nexthop_v4));
811 				}
812 				found = B_TRUE;
813 				*changed = B_TRUE;
814 				break;
815 			}
816 
817 		}
818 		if (!found) {
819 			/*
820 			 * The interface does not have a default router.
821 			 * Log a warning and go on.
822 			 */
823 			logwarn(gettext("Network interface %s"
824 			    " does not have a default router.\n"),
825 			    nif_list[i].name);
826 			/*
827 			 * Set router_addr to 0 so that we will
828 			 * not do anything for this interface.
829 			 */
830 			nif_list[i].router_addr.s_addr = 0;
831 		} else {
832 			num_found++;
833 		}
834 	}
835 	return (num_found);
836 }
837 
838 /*
839  * Examine the ARP table to find ethernet address for default routers.
840  *
841  * Param:
842  *	mib2_ipNetToMdeiaEntry_t *buf: the mib info buffer.
843  *	size_t len: length of buffer.
844  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
845  *		in ethernet address for any default router.
846  *
847  * Return:
848  *	number of ethernet address found.
849  */
850 static int
851 arp_process(mib2_ipNetToMediaEntry_t *buf, size_t len, boolean_t *changed)
852 {
853 	mib2_ipNetToMediaEntry_t 	*rp;
854 	mib2_ipNetToMediaEntry_t	*endp;
855 	int				i;
856 	boolean_t			found;
857 	int				num_found = 0;
858 	uchar_t				*src, *dst;
859 
860 	if (len == 0)
861 		return (0);
862 	endp = buf + (len / sizeof (mib2_ipNetToMediaEntry_t));
863 
864 	for (i = 0; i < num_nif; i++) {
865 		/*
866 		 * Loop thru the arp table entries and find the ethernet
867 		 * address of those default routers.
868 		 */
869 		if (nif_list[i].router_addr.s_addr == 0)
870 			continue;
871 		found = B_FALSE;
872 		for (rp = buf; rp < endp; rp++) {
873 			if (rp->ipNetToMediaNetAddress ==
874 			    nif_list[i].router_addr.s_addr) {
875 				/*
876 				 * Sanity check.  Make sure that this
877 				 * default router is only reachable thru this
878 				 * interface.
879 				 */
880 				if (rp->ipNetToMediaIfIndex.o_length !=
881 				    strlen(nif_list[i].name) ||
882 				    strncmp(rp->ipNetToMediaIfIndex.o_bytes,
883 					nif_list[i].name,
884 					rp->ipNetToMediaIfIndex.o_length) !=
885 				    0) {
886 					break;
887 				}
888 				/* No change, do not do anything. */
889 				if (bcmp(nif_list[i].router_ether_addr,
890 				    rp->ipNetToMediaPhysAddress.o_bytes,
891 				    ETHERADDRL) == 0) {
892 					found = B_TRUE;
893 					continue;
894 				}
895 				dst = nif_list[i].router_ether_addr;
896 				src = (uchar_t *)
897 				    rp->ipNetToMediaPhysAddress.o_bytes;
898 				for (len = ETHERADDRL; len > 0; len--)
899 					*dst++ = *src++;
900 				if (debug) {
901 					int j;
902 					uchar_t *cp;
903 					char err_buf[128];
904 
905 					(void) snprintf(err_buf,
906 					    sizeof (err_buf),
907 					    "Get address for %s: ",
908 					    inet_ntoa(nif_list[i].router_addr));
909 					cp = (uchar_t *)
910 					    nif_list[i].router_ether_addr;
911 					for (j = 0; j < ETHERADDRL; j++) {
912 						(void) sprintf(err_buf +
913 						    strlen(err_buf),
914 						    "%02x:", 0xff & cp[j]);
915 					}
916 					(void) sprintf(err_buf +
917 					    strlen(err_buf) - 1, "\n");
918 					logdebug(err_buf);
919 				}
920 				found = B_TRUE;
921 				*changed = B_TRUE;
922 			}
923 		}
924 		if (!found) {
925 			logwarn("Cannot reach %s using %s\n",
926 			    inet_ntoa(nif_list[i].router_addr),
927 			    nif_list[i].name);
928 			/* Clear this default router. */
929 			nif_list[i].router_addr.s_addr = 0;
930 		} else {
931 			num_found++;
932 		}
933 	}
934 	return (num_found);
935 }
936 
937 /*
938  * Get IP address of default routers for each interface.
939  *
940  * Param:
941  *	mib_item_t *item: the mib info buffer.
942  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
943  *		in router info.
944  *
945  * Return:
946  *	-1 if there is no router found, 0 otherwise.
947  */
948 static int
949 get_router_ip_addr(mib_item_t *item, boolean_t *changed)
950 {
951 	int found = 0;
952 
953 	for (; item != NULL; item = item->next_item) {
954 		/* NCA does not support IPv6... */
955 		if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_ROUTE))
956 			continue;
957 		/* LINTED */
958 		found += ire_process((mib2_ipRouteEntry_t *)item->valp,
959 		    item->length, changed);
960 	}
961 	if (found == 0)
962 		return (-1);
963 	else
964 		return (0);
965 }
966 
967 /*
968  * Get Ethernet address for each default router from ARP.
969  *
970  * Param:
971  *	mib_item_t *item: the mib info buffer.
972  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
973  *		in ethernet address of router.
974  *
975  * Return:
976  *	-1 if there is no ethernet address found, 0 otherwise.
977  */
978 static int
979 get_router_ether_addr(mib_item_t *item, boolean_t *changed)
980 {
981 	int found = 0;
982 
983 	for (; item != NULL; item = item->next_item) {
984 		/* NCA does not support IPv6... */
985 		if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_MEDIA))
986 			continue;
987 		/* LINTED */
988 		found += arp_process((mib2_ipNetToMediaEntry_t *)item->valp,
989 		    item->length, changed);
990 	}
991 	if (found == 0)
992 		return (-1);
993 	else
994 		return (0);
995 }
996 
997 /*
998  * Ping all default routers.  It just uses system(3F) to call
999  * ping(1M) to do the job...
1000  */
1001 static void
1002 ping_them(void)
1003 {
1004 	int i;
1005 	char ping_cmd[128];
1006 
1007 	for (i = 0; i < num_nif; i++) {
1008 		if (nif_list[i].router_addr.s_addr != 0) {
1009 			(void) snprintf(ping_cmd, sizeof (ping_cmd),
1010 			    "%s %s > /dev/null 2>&1",
1011 			    ping_prog,
1012 			    inet_ntoa(nif_list[i].router_addr));
1013 			(void) system(ping_cmd);
1014 		}
1015 	}
1016 }
1017 
1018 /*
1019  * To get default router info (both IP address and ethernet address) for
1020  * each configured interface from IP.
1021  *
1022  * Param:
1023  *	boolean_t *changed (referenced): set to B_TRUE if there is any change
1024  *		of info.
1025  *
1026  * Return:
1027  *	-1 if there is any error, 0 if everything is fine.
1028  */
1029 static int
1030 get_if_info(boolean_t *changed)
1031 {
1032 	int mib_fd;
1033 	mib_item_t *item;
1034 	boolean_t ip_changed = B_FALSE;
1035 	boolean_t ether_changed = B_FALSE;
1036 
1037 	if ((mib_fd = open(IP_DEV_NAME, O_RDWR)) < 0) {
1038 		logperror("cannot open ip to get router info");
1039 		return (-1);
1040 	}
1041 	if (ioctl(mib_fd, I_PUSH, ARP_MOD_NAME) == -1) {
1042 		logperror("cannot push arp");
1043 		goto err;
1044 	}
1045 
1046 	if ((item = mibget(mib_fd)) == NULL) {
1047 		goto err;
1048 	}
1049 
1050 	if (get_router_ip_addr(item, &ip_changed) < 0) {
1051 		goto err;
1052 	}
1053 	/*
1054 	 * Ping every routers to make sure that ARP has all their ethernet
1055 	 * addresses.
1056 	 */
1057 	ping_them();
1058 	/*
1059 	 * If the router IP address is not changed, its ethernet address
1060 	 * should not be changed.  But just in case there is some IP
1061 	 * failover going on...
1062 	 */
1063 	if (get_router_ether_addr(item, &ether_changed) < 0) {
1064 		goto err;
1065 	}
1066 	(void) close(mib_fd);
1067 	*changed = ip_changed || ether_changed;
1068 	return (0);
1069 err:
1070 	(void) close(mib_fd);
1071 	return (-1);
1072 }
1073 
1074 /*
1075  * To remove the default router from an interface.
1076  *
1077  * Param:
1078  *	struct in_addr gw_addr: the IP address of the default router to be
1079  *	removed.
1080  */
1081 static void
1082 nca_del_nif(struct in_addr gw_addr)
1083 {
1084 	struct nca_set_ioctl nca_ioctl;
1085 	struct strioctl strioc;
1086 	int i;
1087 	int udp_fd, fd;
1088 
1089 	/* Search for the interface for this router. */
1090 	for (i = 0; i < num_nif; i++) {
1091 		if (nif_list[i].router_addr.s_addr == gw_addr.s_addr)
1092 			break;
1093 	}
1094 	if (i == num_nif)
1095 		return;
1096 
1097 	if (ip_domux2fd(&udp_fd, &fd) < 0) {
1098 		logwarn(gettext("Removing interface %s from the"
1099 		    " configuration list.\n"), nif_list[i].name);
1100 		nif_list[i].name[0] = 0;
1101 		return;
1102 	}
1103 	if (ioctl(udp_fd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
1104 		logwarn(gettext("Removing interface %s from the"
1105 		    " configuration list.\n"), nif_list[i].name);
1106 		nif_list[i].name[0] = 0;
1107 		(void) close(udp_fd);
1108 		(void) close(fd);
1109 		return;
1110 	}
1111 
1112 	strioc.ic_cmd = NCA_SET_IF;
1113 	strioc.ic_timout = INFTIM;
1114 	strioc.ic_len = sizeof (nca_ioctl);
1115 	strioc.ic_dp = (char *)&nca_ioctl;
1116 
1117 	nca_ioctl.local_addr = 0;
1118 	(void) memset(nca_ioctl.router_ether_addr, 0, ETHERADDRL);
1119 	nca_ioctl.action = DEL_DEF_ROUTE;
1120 
1121 	if (ioctl(fd, I_STR, &strioc) < 0) {
1122 		logperror("ioctl(NCA_SET_IF) failed");
1123 	}
1124 	ip_plink(udp_fd, fd);
1125 	(void) close(udp_fd);
1126 	(void) close(fd);
1127 
1128 	/* Clear the fields for this interface. */
1129 	nif_list[i].router_addr.s_addr = 0;
1130 	(void) memset(nif_list[i].router_ether_addr, 0, ETHERADDRL);
1131 }
1132 
1133 /*
1134  * Wait for any changes in the routing table.  If there are changes to
1135  * IP address or router ethernet address, send down the info to NCA.
1136  */
1137 static void
1138 daemon_work(void)
1139 {
1140 	int n;
1141 	int i;
1142 	int udp_fd;
1143 	int fd;
1144 	int64_t msg[2048/8];
1145 	struct rt_msghdr *rtm;
1146 	boolean_t changed;
1147 	struct sockaddr_in *sin;
1148 	struct in_addr gw_addr;
1149 	uchar_t *cp;
1150 
1151 	/* Loop forever waiting for any routing changes. */
1152 	for (;;) {
1153 		if (debug) {
1154 			logdebug("Waiting to read routing info...\n");
1155 		}
1156 		n = read(rt_fd, msg, sizeof (msg));
1157 		/* Don't die...  Reinitialize socket and listen again. */
1158 		if (n <= 0) {
1159 			if (debug) {
1160 				logdebug("Routing socket read error.\n");
1161 			}
1162 			(void) close(rt_fd);
1163 			rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
1164 			i = 0;
1165 			while (rt_fd < 0) {
1166 				if (i++ == 0) {
1167 					logperror(gettext("cannot reinitialize"
1168 					    " routing socket"));
1169 				} else if (i > 5) {
1170 					logwarn(gettext("Give up on trying to"
1171 					    " reinitializing routing"
1172 					    " socket\n"));
1173 					exit(1);
1174 				}
1175 				/* May be a transient error... */
1176 				(void) sleep(10);
1177 				rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
1178 			}
1179 		} else {
1180 			rtm = (struct rt_msghdr *)msg;
1181 			if (rtm->rtm_version != RTM_VERSION) {
1182 				logwarn(gettext("Do non understand routing"
1183 				    " socket info.\n"));
1184 				continue;
1185 			}
1186 			if (debug) {
1187 				logdebug("Get routing info.\n");
1188 			}
1189 			switch (rtm->rtm_type) {
1190 			case RTM_DELETE:
1191 			case RTM_OLDDEL:
1192 				sin = (struct sockaddr_in *)(rtm + 1);
1193 				cp = (uchar_t *)sin;
1194 				/* Only handle default route deletion. */
1195 				if ((rtm->rtm_addrs & RTA_DST) &&
1196 				    (sin->sin_addr.s_addr == 0)) {
1197 					if (!(rtm->rtm_addrs & RTA_GATEWAY)) {
1198 						break;
1199 					}
1200 					cp += sizeof (struct sockaddr_in);
1201 					/* LINTED */
1202 					sin = (struct sockaddr_in *)cp;
1203 					gw_addr = sin->sin_addr;
1204 					if (debug) {
1205 						logdebug("Get default route "
1206 						    "removal notice: gw %s\n",
1207 						    inet_ntoa(gw_addr));
1208 					}
1209 					nca_del_nif(gw_addr);
1210 				}
1211 				break;
1212 			case RTM_ADD:
1213 			case RTM_OLDADD:
1214 			case RTM_CHANGE:
1215 				changed = B_FALSE;
1216 				if (get_if_info(&changed) < 0) {
1217 					/* May be a transient error... */
1218 					(void) sleep(10);
1219 					break;
1220 				}
1221 				/* Nothing is changed, do nothing. */
1222 				if (!changed) {
1223 					if (debug) {
1224 						logdebug("Get route change "
1225 						    "notice, but nothing is "
1226 						    "changed for us!");
1227 					}
1228 					break;
1229 				}
1230 				lifr.lifr_addr.ss_family = AF_INET;
1231 				for (i = 0; i < num_nif; i++) {
1232 					int ret;
1233 
1234 					/*
1235 					 * If name is NULL, it means that
1236 					 * we have encontered some problems
1237 					 * when configurating the interface.
1238 					 * So we remove it from the list.
1239 					 */
1240 					if (nif_list[i].name[0] == 0 ||
1241 					    nif_list[i].local_addr.s_addr == 0)
1242 						continue;
1243 					(void) strlcpy(lifr.lifr_name,
1244 					    nif_list[i].name,
1245 					    sizeof (lifr.lifr_name));
1246 					if (ip_domux2fd(&udp_fd, &fd) < 0) {
1247 						logwarn(gettext("Removing"
1248 						    " interface %s from the"
1249 						    " configuration list.\n"),
1250 						    nif_list[i].name);
1251 						nif_list[i].name[0] = 0;
1252 						continue;
1253 					}
1254 					if (ioctl(udp_fd, I_PUNLINK,
1255 					    lifr.lifr_ip_muxid) < 0) {
1256 						logwarn(gettext("Removing"
1257 						    " interface %s from the"
1258 						    " configuration list.\n"),
1259 						    nif_list[i].name);
1260 						nif_list[i].name[0] = 0;
1261 						(void) close(udp_fd);
1262 						(void) close(fd);
1263 						continue;
1264 					}
1265 					if (debug) {
1266 						logdebug("Configuring"
1267 						    " %s\n", nif_list[i].name);
1268 					}
1269 					ret = nca_set_nif(fd,
1270 					    nif_list[i].local_addr,
1271 					    nif_list[i].router_ether_addr);
1272 					ip_plink(udp_fd, fd);
1273 					if (ret < 0) {
1274 						/*
1275 						 * This should not be possible
1276 						 * since if NCA does not
1277 						 * support the ioctl, the
1278 						 * active flag should be
1279 						 * cleared already and this
1280 						 * function should not have
1281 						 * been called at all!
1282 						 */
1283 						logwarn("Daemon dies\n");
1284 						exit(1);
1285 					}
1286 					(void) close(udp_fd);
1287 					(void) close(fd);
1288 				}
1289 				break;
1290 			default:
1291 				continue;
1292 			}
1293 		}
1294 	}
1295 }
1296 
1297 /*
1298  * Make us a daemon.
1299  */
1300 static void
1301 daemon_init(void)
1302 {
1303 	pid_t pid;
1304 
1305 	if ((pid = fork()) == -1) {
1306 		/* Write directly to terminal, instead of syslog. */
1307 		(void) fprintf(stderr, gettext("ncaconfd: cannot fork: %s\n"),
1308 		    strerror(errno));
1309 		exit(1);
1310 	}
1311 	if (pid != 0)
1312 		exit(0);
1313 	(void) setsid();
1314 	/* Fork again so that we will never get a controlling terminal. */
1315 	if ((pid = fork()) == -1) {
1316 		/* Write directly to terminal, instead of syslog. */
1317 		(void) fprintf(stderr, gettext("ncaconfd: cannot fork: %s\n"),
1318 		    strerror(errno));
1319 		exit(1);
1320 	}
1321 	if (pid != 0)
1322 		exit(0);
1323 	(void) chdir("/");
1324 	(void) umask(0);
1325 	(void) fclose(stdin);
1326 	(void) fclose(stdout);
1327 	(void) fclose(stderr);
1328 }
1329 
1330 int
1331 main(int argc, char **argv)
1332 {
1333 	int i, j;
1334 	int c;
1335 	boolean_t active = B_FALSE;
1336 	boolean_t as_daemon = B_TRUE;
1337 
1338 	if (argc == 1) {
1339 		(void) fprintf(stderr, gettext("Usage: %s [-al]"
1340 		    " [interface1 interface2 ...]\n"), argv[0]);
1341 		return (1);
1342 	}
1343 
1344 	(void) setlocale(LC_ALL, "");
1345 #if !defined(TEXT_DOMAIN)
1346 #define	TEXT_DOMAIN "SYS_TEST"
1347 #endif
1348 	(void) textdomain(TEXT_DOMAIN);
1349 
1350 	while ((c = getopt(argc, argv, "adcl")) != EOF) {
1351 		switch (c) {
1352 		case 'a':
1353 			active = B_TRUE;
1354 			break;
1355 		case 'd':
1356 			debug = B_TRUE;
1357 			break;
1358 		case 'c':
1359 			/* Don't run as daemon. */
1360 			as_daemon = B_FALSE;
1361 			break;
1362 		case 'l':
1363 			logging = B_TRUE;
1364 			break;
1365 		default:
1366 			/* -d and -c are "undocumented" options. */
1367 			(void) fprintf(stderr, gettext("Usage: %s [-al]"
1368 			    " [interface1 interface2 ...]\n"), argv[0]);
1369 			return (1);
1370 		}
1371 	}
1372 	num_nif = argc - optind;
1373 	if (num_nif == 0) {
1374 		/* No network interface to proces... */
1375 		(void) fprintf(stderr, gettext("Usage: %s [-al]"
1376 		    " [interface1 interface2 ...]\n"), argv[0]);
1377 		return (0);
1378 	}
1379 	nif_list = calloc(num_nif, sizeof (nif_t));
1380 	if (nif_list == NULL) {
1381 		(void) fprintf(stderr, gettext("ncaconfd: Cannot malloc: %s\n"),
1382 		    strerror(errno));
1383 		return (1);
1384 	}
1385 	for (i = 0, j = optind; i < num_nif; i++, j++) {
1386 		(void) strlcpy(nif_list[i].name, argv[j], LIFNAMSIZ+1);
1387 	}
1388 
1389 	/* Get IP address info for all the intefaces. */
1390 	if (get_if_ip_addr() < 0) {
1391 		if (debug) {
1392 			(void) fprintf(stderr, "ncaconfd: Cannot get IP"
1393 			    " addresses for interfaces.\n");
1394 		}
1395 		return (1);
1396 	}
1397 	if (logging)
1398 		openlog("ncaconfd", LOG_PID, LOG_DAEMON);
1399 	/* No need to run as daemon if NCA is not making active connections. */
1400 	if (active && as_daemon)
1401 		daemon_init();
1402 	if (active) {
1403 		boolean_t changed;
1404 
1405 		/* NCA does not support IPv6... */
1406 		if ((rt_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
1407 			logperror("Cannot open routing socket");
1408 			return (1);
1409 		}
1410 		/*
1411 		 * At boot up time, the default router may not have been
1412 		 * found.  So ignore the error and check later.
1413 		 */
1414 		if (get_if_info(&changed) < 0) {
1415 			if (debug) {
1416 				(void) logwarn("Cannot get"
1417 				    " information from network interface.\n");
1418 			}
1419 		}
1420 	}
1421 	/* Do the set up as daemon (if we are) to save time at boot up... */
1422 	nca_setup(&active);
1423 	if (active)
1424 		daemon_work();
1425 	return (0);
1426 }
1427