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