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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
31 #include <sys/tihdr.h>
43 #include <sys/varargs.h>
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>
51 #include <inet/mib2.h>
53 #include <net/route.h>
54 #include <arpa/inet.h>
57 /* NCA does not support IPv6... */
59 #define NCA_MOD_NAME "nca"
63 #define ARP_MOD_NAME "arp"
66 #define IF_SEPARATOR ':'
68 #define ping_prog "/usr/sbin/ping"
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
];
78 typedef struct mib_item_s
{
79 struct mib_item_s
*next_item
;
86 /* The network interface array. */
87 static nif_t
*nif_list
;
88 /* Number of network interface to process. */
91 /* Interface request to IP. */
92 static struct lifreq lifr
;
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
;
99 /* File descriptor to the routing socket. */
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);
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().
130 syslog(LOG_ERR
, "%s: %m\n", str
);
132 (void) fprintf(stderr
, "ncaconfd: %s: %s\n", str
,
138 * Print out warning messages. The caller should use gettext() to have
139 * the message printed out in the correct language.
143 logwarn(char *fmt
, ...)
149 vsyslog(LOG_WARNING
, fmt
, ap
);
151 (void) fprintf(stderr
, "ncaconfd: ");
152 (void) vfprintf(stderr
, fmt
, ap
);
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.
163 logdebug(char *fmt
, ...)
169 vsyslog(LOG_WARNING
, fmt
, ap
);
171 (void) fprintf(stderr
, "ncaconfd: ");
172 (void) vfprintf(stderr
, fmt
, ap
);
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.
183 * int *udp_fd: (referenced) fd to /dev/udp (upper IP stream).
184 * int *fd: (referenced) fd to the lower IP stream.
187 * -1 if operation fails, 0 otherwise.
190 ip_domux2fd(int *udp_fd
, int *fd
)
194 if ((ip_fd
= open(IP_DEV_NAME
, O_RDWR
)) < 0) {
195 logperror("Cannot open IP");
198 if ((*udp_fd
= open(UDP_DEV_NAME
, O_RDWR
)) < 0) {
199 logperror("Cannot open UDP");
203 if (ioctl(ip_fd
, SIOCGLIFMUXID
, (caddr_t
)&lifr
) < 0) {
204 logperror("ioctl(SIOCGLIFMUXID) failed");
209 logdebug("ARP_muxid %d IP_muxid %d\n", lifr
.lifr_arp_muxid
,
212 if ((*fd
= ioctl(*udp_fd
, _I_MUXID2FD
, lifr
.lifr_ip_muxid
)) < 0) {
213 logperror("ioctl(_I_MUXID2FD) failed");
215 (void) close(*udp_fd
);
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.
230 * int udp_fd: fd to /dev/udp (upper IP stream).
231 * int fd: fd to the lower IP stream.
234 ip_plink(int udp_fd
, int fd
)
238 if ((mux_id
= ioctl(udp_fd
, I_PLINK
, fd
)) < 0) {
239 logperror("ioctl(I_PLINK) failed");
243 logdebug("New IP_muxid %d\n", mux_id
);
245 lifr
.lifr_ip_muxid
= mux_id
;
246 if (ioctl(udp_fd
, SIOCSLIFMUXID
, (caddr_t
)&lifr
) < 0) {
247 logperror("ioctl(SIOCSLIFMUXID) failed");
252 #define FOUND_NONE -2
254 * Find the proper position to insert NCA, which is just below IP.
257 * int fd: fd to the lower IP stream.
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.
271 struct str_list strlist
;
272 boolean_t found_ip
= B_FALSE
;
273 boolean_t found_nca
= B_FALSE
;
275 if ((num_mods
= ioctl(fd
, I_LIST
, NULL
)) < 0) {
276 logperror("ioctl(I_LIST) failed");
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");
286 if (ioctl(fd
, I_LIST
, (caddr_t
)&strlist
) < 0) {
287 logperror("ioctl(I_LIST) failed");
289 for (i
= 0; i
< strlist
.sl_nmods
; i
++) {
290 if (strcmp(IP_MOD_NAME
,
291 strlist
.sl_modlist
[i
].l_name
)
295 * NCA should be just below
299 } else if (strncmp(NCA_MOD_NAME
,
300 strlist
.sl_modlist
[i
].l_name
,
301 strlen(NCA_MOD_NAME
)) == 0) {
306 free(strlist
.sl_modlist
);
311 } else if (found_ip
) {
313 logdebug("NCA is at position %d in the stream.\n", pos
);
318 logdebug("Cannot find IP??\n");
325 * To set the local IP address and default router ethernet address.
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.
334 * -1 if the system does not support this NCA ioctl(), 0 otherwise.
337 nca_set_nif(int fd
, struct in_addr local_addr
, uchar_t
*ether_addr
)
339 struct nca_set_ioctl nca_ioctl
;
340 struct strioctl strioc
;
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
;
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
;
355 if (ioctl(fd
, I_STR
, &strioc
) < 0) {
356 logperror("ioctl(NCA_SET_IF) failed");
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
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.
374 nca_setup(boolean_t
*active
)
379 struct strmodconf mod
;
380 /* 128 is enough because interface name can only be LIFNAMSIZ long. */
383 mod
.mod_name
= NCA_MOD_NAME
;
384 lifr
.lifr_addr
.ss_family
= AF_INET
;
385 for (i
= 0; i
< num_nif
; i
++) {
387 logdebug("Plumbing NCA for %s\n", nif_list
[i
].name
);
389 /* This interface does not exist according to IP. */
390 if (nif_list
[i
].local_addr
.s_addr
== 0) {
393 (void) strlcpy(lifr
.lifr_name
, nif_list
[i
].name
,
394 sizeof (lifr
.lifr_name
));
396 if (ip_domux2fd(&udp_fd
, &fd
) < 0) {
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
);
403 (void) close(udp_fd
);
407 if ((mod
.pos
= find_nca_pos(fd
)) < 0) {
408 if (mod
.pos
== FOUND_NCA
) {
410 logdebug("Find NCA in the %s"
411 " stream\n", nif_list
[i
].name
);
413 /* Just skip plumbing NCA. */
417 logdebug("Cannot find pos for %s\n",
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
);
430 * Only do the following if NCA is also used to make
431 * outgoing connections, and all necessary info is
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) {
439 * The system does not support this ioctl()!
440 * Skip all active stack processing but
441 * continue to plumb NCA.
443 logwarn("NCA does not support active stack!");
448 ip_plink(udp_fd
, fd
);
449 (void) close(udp_fd
);
455 * To get IP address of network interface from IP.
464 struct sockaddr_in
*sin
;
469 /* NCA only supports IPv4... */
470 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
471 logperror(gettext("Cannot open socket"));
474 lifn
.lifn_family
= AF_UNSPEC
;
476 if (ioctl(sock
, SIOCGLIFNUM
, (char *)&lifn
) < 0) {
477 logperror(gettext("ioctl(SIOCGLIFNUM) failed"));
481 buf
= (char *)calloc(lifn
.lifn_count
, sizeof (struct lifreq
));
483 logperror(gettext("calloc() failed"));
488 lifc
.lifc_family
= AF_UNSPEC
;
490 lifc
.lifc_len
= lifn
.lifn_count
* sizeof (struct lifreq
);
493 if (ioctl(sock
, SIOCGLIFCONF
, (char *)&lifc
) < 0) {
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.
499 logperror(gettext("ioctl(SIOCGLIFCONF) failed"));
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
)
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
;
517 logdebug("IP address of %s: %s\n",
519 inet_ntoa(sin
->sin_addr
));
526 * The interface does not exist according to IP!
527 * Log a warning and go on.
529 logwarn(gettext("Network interface %s"
530 " does not exist!\n"), nif_list
[i
].name
);
532 * Set local_addr to 0 so that nca_setup() will
533 * not do anything for this interface.
535 nif_list
[i
].local_addr
.s_addr
= 0;
544 * Get MIB2 info from IP.
547 * int sd: descriptor to IP to send down mib request.
555 struct strbuf ctlbuf
, databuf
;
557 struct T_optmgmt_req
*tor
= (struct T_optmgmt_req
*)buf
;
559 struct T_optmgmt_ack
*toa
= (struct T_optmgmt_ack
*)buf
;
561 struct T_error_ack
*tea
= (struct T_error_ack
*)buf
;
563 mib_item_t
*first_item
= (mib_item_t
*)0;
564 mib_item_t
*last_item
= (mib_item_t
*)0;
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 */
577 ctlbuf
.len
= tor
->OPT_length
+ tor
->OPT_offset
;
579 if (putmsg(sd
, &ctlbuf
, (struct strbuf
*)0, flags
) == -1) {
580 logperror("mibget: putmsg(ctl) failed");
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.
590 req
= (struct opthdr
*)&toa
[1];
591 ctlbuf
.maxlen
= sizeof (buf
);
595 getcode
= getmsg(sd
, &ctlbuf
, (struct strbuf
*)0, &flags
);
597 logperror("mibget getmsg(ctl) failed");
599 logdebug("# level name len\n");
601 for (last_item
= first_item
; last_item
;
602 last_item
= last_item
->next_item
)
603 (void) printf("%d %4d %5d %d\n",
612 ctlbuf
.len
>= sizeof (struct T_optmgmt_ack
) &&
613 toa
->PRIM_type
== T_OPTMGMT_ACK
&&
614 toa
->MGMT_flags
== T_SUCCESS
&&
617 logdebug("mibget getmsg() %d returned "
618 "EOD (level %ld, name %ld)\n",
619 j
, req
->level
, req
->name
);
621 return (first_item
); /* this is EOD msg */
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
;
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
);
650 temp
= (mib_item_t
*)malloc(sizeof (mib_item_t
));
652 logperror("mibget malloc failed");
656 last_item
->next_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
);
666 databuf
.maxlen
= last_item
->length
;
667 databuf
.buf
= last_item
->valp
;
670 getcode
= getmsg(sd
, (struct strbuf
*)0, &databuf
, &flags
);
672 logperror("mibget getmsg(data) failed");
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
);
685 last_item
= first_item
;
686 first_item
= first_item
->next_item
;
693 * Examine the IPv4 routing table for default routers. For each interface,
694 * find its default router.
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
703 * number of default router found.
706 ire_process(mib2_ipRouteEntry_t
*buf
, size_t len
, boolean_t
*changed
)
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];
722 endp
= buf
+ (len
/ sizeof (mib2_ipRouteEntry_t
));
724 for (i
= 0; i
< num_nif
; i
++) {
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.
731 for (rp
= buf
; rp
< endp
; rp
++) {
733 * NCA is only interested in default routes associated
736 if (!(rp
->ipRouteInfo
.re_ire_type
& IRE_DEFAULT
)) {
739 /* Get the nexthop address. */
740 nexthop_v4
.s_addr
= rp
->ipRouteNextHop
;
743 * Right now, not all IREs have the interface name
744 * it is associated with.
746 if (rp
->ipRouteIfIndex
.o_length
== 0) {
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
754 for (rp1
= buf
; rp1
< endp
; rp1
++) {
756 if (!(rp1
->ipRouteInfo
.re_ire_type
&
762 * Determine the interface IRE that
763 * matches the nexthop. i.e.
764 * (IRE addr & IRE mask) ==
765 * (nexthop & IRE mask)
767 if ((rp1
->ipRouteDest
& rp1
->ipRouteMask
) ==
768 (nexthop_v4
.s_addr
& rp1
->ipRouteMask
)) {
770 * We found the interface to go to
771 * the default router. Check the
774 /* Can this be possible?? */
775 if (rp1
->ipRouteIfIndex
.o_length
== 0)
781 } /* End inner for loop. */
786 ifname_len
= MIN(rp2
->ipRouteIfIndex
.o_length
,
787 sizeof (ifname
) - 1);
788 (void) memcpy(ifname
, rp2
->ipRouteIfIndex
.o_bytes
,
790 ifname
[ifname_len
] = '\0';
791 if (ifname
[0] == '\0')
793 cp
= strchr(ifname
, IF_SEPARATOR
);
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
) {
805 nif_list
[i
].router_addr
.s_addr
=
808 logdebug("Get default"
809 " router for %s: %s\n", ifname
,
810 inet_ntoa(nexthop_v4
));
820 * The interface does not have a default router.
821 * Log a warning and go on.
823 logwarn(gettext("Network interface %s"
824 " does not have a default router.\n"),
827 * Set router_addr to 0 so that we will
828 * not do anything for this interface.
830 nif_list
[i
].router_addr
.s_addr
= 0;
839 * Examine the ARP table to find ethernet address for default routers.
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.
848 * number of ethernet address found.
851 arp_process(mib2_ipNetToMediaEntry_t
*buf
, size_t len
, boolean_t
*changed
)
853 mib2_ipNetToMediaEntry_t
*rp
;
854 mib2_ipNetToMediaEntry_t
*endp
;
862 endp
= buf
+ (len
/ sizeof (mib2_ipNetToMediaEntry_t
));
864 for (i
= 0; i
< num_nif
; i
++) {
866 * Loop thru the arp table entries and find the ethernet
867 * address of those default routers.
869 if (nif_list
[i
].router_addr
.s_addr
== 0)
872 for (rp
= buf
; rp
< endp
; rp
++) {
873 if (rp
->ipNetToMediaNetAddress
==
874 nif_list
[i
].router_addr
.s_addr
) {
876 * Sanity check. Make sure that this
877 * default router is only reachable thru this
880 if (rp
->ipNetToMediaIfIndex
.o_length
!=
881 strlen(nif_list
[i
].name
) ||
882 strncmp(rp
->ipNetToMediaIfIndex
.o_bytes
,
884 rp
->ipNetToMediaIfIndex
.o_length
) !=
888 /* No change, do not do anything. */
889 if (bcmp(nif_list
[i
].router_ether_addr
,
890 rp
->ipNetToMediaPhysAddress
.o_bytes
,
895 dst
= nif_list
[i
].router_ether_addr
;
897 rp
->ipNetToMediaPhysAddress
.o_bytes
;
898 for (len
= ETHERADDRL
; len
> 0; len
--)
905 (void) snprintf(err_buf
,
907 "Get address for %s: ",
908 inet_ntoa(nif_list
[i
].router_addr
));
910 nif_list
[i
].router_ether_addr
;
911 for (j
= 0; j
< ETHERADDRL
; j
++) {
912 (void) sprintf(err_buf
+
914 "%02x:", 0xff & cp
[j
]);
916 (void) sprintf(err_buf
+
917 strlen(err_buf
) - 1, "\n");
925 logwarn("Cannot reach %s using %s\n",
926 inet_ntoa(nif_list
[i
].router_addr
),
928 /* Clear this default router. */
929 nif_list
[i
].router_addr
.s_addr
= 0;
938 * Get IP address of default routers for each interface.
941 * mib_item_t *item: the mib info buffer.
942 * boolean_t *changed (referenced): set to B_TRUE if there is any change
946 * -1 if there is no router found, 0 otherwise.
949 get_router_ip_addr(mib_item_t
*item
, boolean_t
*changed
)
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
))
958 found
+= ire_process((mib2_ipRouteEntry_t
*)item
->valp
,
959 item
->length
, changed
);
968 * Get Ethernet address for each default router from ARP.
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.
976 * -1 if there is no ethernet address found, 0 otherwise.
979 get_router_ether_addr(mib_item_t
*item
, boolean_t
*changed
)
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
))
988 found
+= arp_process((mib2_ipNetToMediaEntry_t
*)item
->valp
,
989 item
->length
, changed
);
998 * Ping all default routers. It just uses system(3F) to call
999 * ping(1M) to do the job...
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",
1012 inet_ntoa(nif_list
[i
].router_addr
));
1013 (void) system(ping_cmd
);
1019 * To get default router info (both IP address and ethernet address) for
1020 * each configured interface from IP.
1023 * boolean_t *changed (referenced): set to B_TRUE if there is any change
1027 * -1 if there is any error, 0 if everything is fine.
1030 get_if_info(boolean_t
*changed
)
1034 boolean_t ip_changed
= B_FALSE
;
1035 boolean_t ether_changed
= B_FALSE
;
1037 if ((mib_fd
= open(IP_DEV_NAME
, O_RDWR
)) < 0) {
1038 logperror("cannot open ip to get router info");
1041 if (ioctl(mib_fd
, I_PUSH
, ARP_MOD_NAME
) == -1) {
1042 logperror("cannot push arp");
1046 if ((item
= mibget(mib_fd
)) == NULL
) {
1050 if (get_router_ip_addr(item
, &ip_changed
) < 0) {
1054 * Ping every routers to make sure that ARP has all their ethernet
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...
1063 if (get_router_ether_addr(item
, ðer_changed
) < 0) {
1066 (void) close(mib_fd
);
1067 *changed
= ip_changed
|| ether_changed
;
1070 (void) close(mib_fd
);
1075 * To remove the default router from an interface.
1078 * struct in_addr gw_addr: the IP address of the default router to be
1082 nca_del_nif(struct in_addr gw_addr
)
1084 struct nca_set_ioctl nca_ioctl
;
1085 struct strioctl strioc
;
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
)
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;
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
);
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
;
1117 nca_ioctl
.local_addr
= 0;
1118 (void) memset(nca_ioctl
.router_ether_addr
, 0, ETHERADDRL
);
1119 nca_ioctl
.action
= DEL_DEF_ROUTE
;
1121 if (ioctl(fd
, I_STR
, &strioc
) < 0) {
1122 logperror("ioctl(NCA_SET_IF) failed");
1124 ip_plink(udp_fd
, fd
);
1125 (void) close(udp_fd
);
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
);
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.
1144 int64_t msg
[2048/8];
1145 struct rt_msghdr
*rtm
;
1147 struct sockaddr_in
*sin
;
1148 struct in_addr gw_addr
;
1151 /* Loop forever waiting for any routing changes. */
1154 logdebug("Waiting to read routing info...\n");
1156 n
= read(rt_fd
, msg
, sizeof (msg
));
1157 /* Don't die... Reinitialize socket and listen again. */
1160 logdebug("Routing socket read error.\n");
1162 (void) close(rt_fd
);
1163 rt_fd
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
);
1167 logperror(gettext("cannot reinitialize"
1168 " routing socket"));
1170 logwarn(gettext("Give up on trying to"
1171 " reinitializing routing"
1175 /* May be a transient error... */
1177 rt_fd
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
);
1180 rtm
= (struct rt_msghdr
*)msg
;
1181 if (rtm
->rtm_version
!= RTM_VERSION
) {
1182 logwarn(gettext("Do non understand routing"
1183 " socket info.\n"));
1187 logdebug("Get routing info.\n");
1189 switch (rtm
->rtm_type
) {
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
)) {
1200 cp
+= sizeof (struct sockaddr_in
);
1202 sin
= (struct sockaddr_in
*)cp
;
1203 gw_addr
= sin
->sin_addr
;
1205 logdebug("Get default route "
1206 "removal notice: gw %s\n",
1207 inet_ntoa(gw_addr
));
1209 nca_del_nif(gw_addr
);
1216 if (get_if_info(&changed
) < 0) {
1217 /* May be a transient error... */
1221 /* Nothing is changed, do nothing. */
1224 logdebug("Get route change "
1225 "notice, but nothing is "
1230 lifr
.lifr_addr
.ss_family
= AF_INET
;
1231 for (i
= 0; i
< num_nif
; i
++) {
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.
1240 if (nif_list
[i
].name
[0] == 0 ||
1241 nif_list
[i
].local_addr
.s_addr
== 0)
1243 (void) strlcpy(lifr
.lifr_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"),
1251 nif_list
[i
].name
[0] = 0;
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"),
1260 nif_list
[i
].name
[0] = 0;
1261 (void) close(udp_fd
);
1266 logdebug("Configuring"
1267 " %s\n", nif_list
[i
].name
);
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
);
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!
1283 logwarn("Daemon dies\n");
1286 (void) close(udp_fd
);
1305 if ((pid
= fork()) == -1) {
1306 /* Write directly to terminal, instead of syslog. */
1307 (void) fprintf(stderr
, gettext("ncaconfd: cannot fork: %s\n"),
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"),
1325 (void) fclose(stdin
);
1326 (void) fclose(stdout
);
1327 (void) fclose(stderr
);
1331 main(int argc
, char **argv
)
1335 boolean_t active
= B_FALSE
;
1336 boolean_t as_daemon
= B_TRUE
;
1339 (void) fprintf(stderr
, gettext("Usage: %s [-al]"
1340 " [interface1 interface2 ...]\n"), argv
[0]);
1344 (void) setlocale(LC_ALL
, "");
1345 #if !defined(TEXT_DOMAIN)
1346 #define TEXT_DOMAIN "SYS_TEST"
1348 (void) textdomain(TEXT_DOMAIN
);
1350 while ((c
= getopt(argc
, argv
, "adcl")) != EOF
) {
1359 /* Don't run as daemon. */
1360 as_daemon
= B_FALSE
;
1366 /* -d and -c are "undocumented" options. */
1367 (void) fprintf(stderr
, gettext("Usage: %s [-al]"
1368 " [interface1 interface2 ...]\n"), argv
[0]);
1372 num_nif
= argc
- optind
;
1374 /* No network interface to proces... */
1375 (void) fprintf(stderr
, gettext("Usage: %s [-al]"
1376 " [interface1 interface2 ...]\n"), argv
[0]);
1379 nif_list
= calloc(num_nif
, sizeof (nif_t
));
1380 if (nif_list
== NULL
) {
1381 (void) fprintf(stderr
, gettext("ncaconfd: Cannot malloc: %s\n"),
1385 for (i
= 0, j
= optind
; i
< num_nif
; i
++, j
++) {
1386 (void) strlcpy(nif_list
[i
].name
, argv
[j
], LIFNAMSIZ
+1);
1389 /* Get IP address info for all the intefaces. */
1390 if (get_if_ip_addr() < 0) {
1392 (void) fprintf(stderr
, "ncaconfd: Cannot get IP"
1393 " addresses for interfaces.\n");
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
)
1405 /* NCA does not support IPv6... */
1406 if ((rt_fd
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)) < 0) {
1407 logperror("Cannot open routing socket");
1411 * At boot up time, the default router may not have been
1412 * found. So ignore the error and check later.
1414 if (get_if_info(&changed
) < 0) {
1416 (void) logwarn("Cannot get"
1417 " information from network interface.\n");
1421 /* Do the set up as daemon (if we are) to save time at boot up... */