1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */
29*7c478bd9Sstevel@tonic-gate
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
32*7c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California.
33*7c478bd9Sstevel@tonic-gate */
34*7c478bd9Sstevel@tonic-gate
35*7c478bd9Sstevel@tonic-gate /*
36*7c478bd9Sstevel@tonic-gate * Routing Table Management Daemon
37*7c478bd9Sstevel@tonic-gate */
38*7c478bd9Sstevel@tonic-gate #include "defs.h"
39*7c478bd9Sstevel@tonic-gate
40*7c478bd9Sstevel@tonic-gate boolean_t install = _B_TRUE; /* update kernel routing table */
41*7c478bd9Sstevel@tonic-gate struct rthash *net_hashes[IPV6_ABITS + 1];
42*7c478bd9Sstevel@tonic-gate
43*7c478bd9Sstevel@tonic-gate /*
44*7c478bd9Sstevel@tonic-gate * Size of routing socket message used by in.ripngd which includes the header,
45*7c478bd9Sstevel@tonic-gate * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6)
46*7c478bd9Sstevel@tonic-gate * plus space for the RTA_IFP (a sockaddr_dl).
47*7c478bd9Sstevel@tonic-gate */
48*7c478bd9Sstevel@tonic-gate #define RIPNG_RTM_MSGLEN sizeof (struct rt_msghdr) + \
49*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \
50*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \
51*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \
52*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl)
53*7c478bd9Sstevel@tonic-gate
54*7c478bd9Sstevel@tonic-gate static int rtmseq; /* rtm_seq sequence number */
55*7c478bd9Sstevel@tonic-gate static int rtsock; /* Routing socket */
56*7c478bd9Sstevel@tonic-gate static struct rt_msghdr *rt_msg; /* Routing socket message */
57*7c478bd9Sstevel@tonic-gate static struct sockaddr_in6 *rta_dst; /* RTA_DST sockaddr */
58*7c478bd9Sstevel@tonic-gate static struct sockaddr_in6 *rta_gateway; /* RTA_GATEWAY sockaddr */
59*7c478bd9Sstevel@tonic-gate static struct sockaddr_in6 *rta_netmask; /* RTA_NETMASK sockaddr */
60*7c478bd9Sstevel@tonic-gate static struct sockaddr_dl *rta_ifp; /* RTA_IFP sockaddr */
61*7c478bd9Sstevel@tonic-gate
62*7c478bd9Sstevel@tonic-gate /* simulate vax insque and remque instructions. */
63*7c478bd9Sstevel@tonic-gate
64*7c478bd9Sstevel@tonic-gate typedef struct vq {
65*7c478bd9Sstevel@tonic-gate caddr_t fwd, back;
66*7c478bd9Sstevel@tonic-gate } vq_t;
67*7c478bd9Sstevel@tonic-gate
68*7c478bd9Sstevel@tonic-gate #define insque(e, p) ((vq_t *)(e))->back = (caddr_t)(p); \
69*7c478bd9Sstevel@tonic-gate ((vq_t *)(e))->fwd = \
70*7c478bd9Sstevel@tonic-gate (caddr_t)((vq_t *)((vq_t *)(p))->fwd); \
71*7c478bd9Sstevel@tonic-gate ((vq_t *)((vq_t *)(p))->fwd)->back = (caddr_t)(e); \
72*7c478bd9Sstevel@tonic-gate ((vq_t *)(p))->fwd = (caddr_t)(e);
73*7c478bd9Sstevel@tonic-gate
74*7c478bd9Sstevel@tonic-gate #define remque(e) ((vq_t *)((vq_t *)(e))->back)->fwd = \
75*7c478bd9Sstevel@tonic-gate (caddr_t)((vq_t *)(e))->fwd; \
76*7c478bd9Sstevel@tonic-gate ((vq_t *)((vq_t *)(e))->fwd)->back = \
77*7c478bd9Sstevel@tonic-gate (caddr_t)((vq_t *)(e))->back; \
78*7c478bd9Sstevel@tonic-gate ((vq_t *)(e))->fwd = NULL; \
79*7c478bd9Sstevel@tonic-gate ((vq_t *)(e))->back = NULL;
80*7c478bd9Sstevel@tonic-gate
81*7c478bd9Sstevel@tonic-gate static void
log_change(int level,struct rt_entry * orig,struct rt_entry * new)82*7c478bd9Sstevel@tonic-gate log_change(int level, struct rt_entry *orig, struct rt_entry *new)
83*7c478bd9Sstevel@tonic-gate {
84*7c478bd9Sstevel@tonic-gate char buf1[INET6_ADDRSTRLEN];
85*7c478bd9Sstevel@tonic-gate char buf2[INET6_ADDRSTRLEN];
86*7c478bd9Sstevel@tonic-gate char buf3[INET6_ADDRSTRLEN];
87*7c478bd9Sstevel@tonic-gate
88*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *) &new->rt_dst, buf1, sizeof (buf1));
89*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *) &orig->rt_router, buf2,
90*7c478bd9Sstevel@tonic-gate sizeof (buf2));
91*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *) &new->rt_router, buf3,
92*7c478bd9Sstevel@tonic-gate sizeof (buf3));
93*7c478bd9Sstevel@tonic-gate
94*7c478bd9Sstevel@tonic-gate syslog(level, "\tdst %s from gw %s if %s to gw %s if %s metric %d",
95*7c478bd9Sstevel@tonic-gate buf1, buf2,
96*7c478bd9Sstevel@tonic-gate (orig->rt_ifp != NULL && orig->rt_ifp->int_name != NULL) ?
97*7c478bd9Sstevel@tonic-gate orig->rt_ifp->int_name : "(noname)",
98*7c478bd9Sstevel@tonic-gate buf3,
99*7c478bd9Sstevel@tonic-gate (new->rt_ifp != NULL && new->rt_ifp->int_name != NULL) ?
100*7c478bd9Sstevel@tonic-gate new->rt_ifp->int_name : "(noname)", new->rt_metric);
101*7c478bd9Sstevel@tonic-gate }
102*7c478bd9Sstevel@tonic-gate
103*7c478bd9Sstevel@tonic-gate static void
log_single(int level,struct rt_entry * rt)104*7c478bd9Sstevel@tonic-gate log_single(int level, struct rt_entry *rt)
105*7c478bd9Sstevel@tonic-gate {
106*7c478bd9Sstevel@tonic-gate char buf1[INET6_ADDRSTRLEN];
107*7c478bd9Sstevel@tonic-gate char buf2[INET6_ADDRSTRLEN];
108*7c478bd9Sstevel@tonic-gate
109*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1));
110*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&rt->rt_router, buf2, sizeof (buf2));
111*7c478bd9Sstevel@tonic-gate
112*7c478bd9Sstevel@tonic-gate syslog(level, "\tdst %s gw %s if %s metric %d",
113*7c478bd9Sstevel@tonic-gate buf1, buf2,
114*7c478bd9Sstevel@tonic-gate (rt->rt_ifp != NULL && rt->rt_ifp->int_name != NULL) ?
115*7c478bd9Sstevel@tonic-gate rt->rt_ifp->int_name : "(noname)",
116*7c478bd9Sstevel@tonic-gate rt->rt_metric);
117*7c478bd9Sstevel@tonic-gate }
118*7c478bd9Sstevel@tonic-gate
119*7c478bd9Sstevel@tonic-gate /*
120*7c478bd9Sstevel@tonic-gate * Computes a hash by XOR-ing the (up to sixteen) octets that make up an IPv6
121*7c478bd9Sstevel@tonic-gate * address. This function assumes that that there are no one-bits in the
122*7c478bd9Sstevel@tonic-gate * address beyond the prefix length.
123*7c478bd9Sstevel@tonic-gate */
124*7c478bd9Sstevel@tonic-gate static uint8_t
rthash(struct in6_addr * dst,int prefix_length)125*7c478bd9Sstevel@tonic-gate rthash(struct in6_addr *dst, int prefix_length)
126*7c478bd9Sstevel@tonic-gate {
127*7c478bd9Sstevel@tonic-gate uint8_t val = 0;
128*7c478bd9Sstevel@tonic-gate int i;
129*7c478bd9Sstevel@tonic-gate
130*7c478bd9Sstevel@tonic-gate for (i = 0; prefix_length > 0; prefix_length -= 8, i++)
131*7c478bd9Sstevel@tonic-gate val ^= dst->s6_addr[i];
132*7c478bd9Sstevel@tonic-gate return (val);
133*7c478bd9Sstevel@tonic-gate }
134*7c478bd9Sstevel@tonic-gate
135*7c478bd9Sstevel@tonic-gate /*
136*7c478bd9Sstevel@tonic-gate * Given a prefix length, fill in the struct in6_addr representing an IPv6
137*7c478bd9Sstevel@tonic-gate * netmask.
138*7c478bd9Sstevel@tonic-gate */
139*7c478bd9Sstevel@tonic-gate static void
rtmask_to_bits(uint_t prefix_length,struct in6_addr * prefix)140*7c478bd9Sstevel@tonic-gate rtmask_to_bits(uint_t prefix_length, struct in6_addr *prefix)
141*7c478bd9Sstevel@tonic-gate {
142*7c478bd9Sstevel@tonic-gate uint_t mask = 0xff;
143*7c478bd9Sstevel@tonic-gate int i;
144*7c478bd9Sstevel@tonic-gate
145*7c478bd9Sstevel@tonic-gate bzero((caddr_t)prefix, sizeof (struct in6_addr));
146*7c478bd9Sstevel@tonic-gate for (i = 0; prefix_length >= 8; prefix_length -= 8, i++)
147*7c478bd9Sstevel@tonic-gate prefix->s6_addr[i] = 0xff;
148*7c478bd9Sstevel@tonic-gate mask = (mask << (8 - prefix_length));
149*7c478bd9Sstevel@tonic-gate if (mask != 0)
150*7c478bd9Sstevel@tonic-gate prefix->s6_addr[i] = mask;
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate
153*7c478bd9Sstevel@tonic-gate void
rtcreate_prefix(struct in6_addr * p1,struct in6_addr * dst,int bits)154*7c478bd9Sstevel@tonic-gate rtcreate_prefix(struct in6_addr *p1, struct in6_addr *dst, int bits)
155*7c478bd9Sstevel@tonic-gate {
156*7c478bd9Sstevel@tonic-gate uchar_t mask;
157*7c478bd9Sstevel@tonic-gate int j;
158*7c478bd9Sstevel@tonic-gate
159*7c478bd9Sstevel@tonic-gate for (j = 0; bits >= 8; bits -= 8, j++)
160*7c478bd9Sstevel@tonic-gate dst->s6_addr[j] = p1->s6_addr[j];
161*7c478bd9Sstevel@tonic-gate
162*7c478bd9Sstevel@tonic-gate if (bits != 0) {
163*7c478bd9Sstevel@tonic-gate mask = 0xff << (8 - bits);
164*7c478bd9Sstevel@tonic-gate dst->s6_addr[j] = p1->s6_addr[j] & mask;
165*7c478bd9Sstevel@tonic-gate j++;
166*7c478bd9Sstevel@tonic-gate }
167*7c478bd9Sstevel@tonic-gate
168*7c478bd9Sstevel@tonic-gate for (; j < 16; j++)
169*7c478bd9Sstevel@tonic-gate dst->s6_addr[j] = 0;
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate
172*7c478bd9Sstevel@tonic-gate /*
173*7c478bd9Sstevel@tonic-gate * Lookup dst in the tables for an exact match.
174*7c478bd9Sstevel@tonic-gate */
175*7c478bd9Sstevel@tonic-gate struct rt_entry *
rtlookup(struct in6_addr * dst,int prefix_length)176*7c478bd9Sstevel@tonic-gate rtlookup(struct in6_addr *dst, int prefix_length)
177*7c478bd9Sstevel@tonic-gate {
178*7c478bd9Sstevel@tonic-gate struct rt_entry *rt;
179*7c478bd9Sstevel@tonic-gate struct rthash *rh;
180*7c478bd9Sstevel@tonic-gate uint_t hash;
181*7c478bd9Sstevel@tonic-gate
182*7c478bd9Sstevel@tonic-gate if (net_hashes[prefix_length] == NULL)
183*7c478bd9Sstevel@tonic-gate return (NULL);
184*7c478bd9Sstevel@tonic-gate
185*7c478bd9Sstevel@tonic-gate hash = rthash(dst, prefix_length);
186*7c478bd9Sstevel@tonic-gate
187*7c478bd9Sstevel@tonic-gate rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK];
188*7c478bd9Sstevel@tonic-gate
189*7c478bd9Sstevel@tonic-gate for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
190*7c478bd9Sstevel@tonic-gate if (rt->rt_hash != hash)
191*7c478bd9Sstevel@tonic-gate continue;
192*7c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&rt->rt_dst, dst) &&
193*7c478bd9Sstevel@tonic-gate rt->rt_prefix_length == prefix_length)
194*7c478bd9Sstevel@tonic-gate return (rt);
195*7c478bd9Sstevel@tonic-gate }
196*7c478bd9Sstevel@tonic-gate return (NULL);
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate
199*7c478bd9Sstevel@tonic-gate /*
200*7c478bd9Sstevel@tonic-gate * Given an IPv6 prefix (destination and prefix length), a gateway, an
201*7c478bd9Sstevel@tonic-gate * interface name and route flags, send down the requested command returning
202*7c478bd9Sstevel@tonic-gate * the return value and errno (in the case of error) from the write() on the
203*7c478bd9Sstevel@tonic-gate * routing socket.
204*7c478bd9Sstevel@tonic-gate */
205*7c478bd9Sstevel@tonic-gate static int
rtcmd(uchar_t type,struct in6_addr * dst,struct in6_addr * gateway,uint_t prefix_length,char * name,int flags)206*7c478bd9Sstevel@tonic-gate rtcmd(uchar_t type, struct in6_addr *dst, struct in6_addr *gateway,
207*7c478bd9Sstevel@tonic-gate uint_t prefix_length, char *name, int flags)
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate int rlen;
210*7c478bd9Sstevel@tonic-gate
211*7c478bd9Sstevel@tonic-gate rta_ifp->sdl_index = if_nametoindex(name);
212*7c478bd9Sstevel@tonic-gate if (rta_ifp->sdl_index == 0)
213*7c478bd9Sstevel@tonic-gate return (-1);
214*7c478bd9Sstevel@tonic-gate
215*7c478bd9Sstevel@tonic-gate rta_dst->sin6_addr = *dst;
216*7c478bd9Sstevel@tonic-gate rta_gateway->sin6_addr = *gateway;
217*7c478bd9Sstevel@tonic-gate rtmask_to_bits(prefix_length, &rta_netmask->sin6_addr);
218*7c478bd9Sstevel@tonic-gate
219*7c478bd9Sstevel@tonic-gate rt_msg->rtm_type = type;
220*7c478bd9Sstevel@tonic-gate rt_msg->rtm_flags = flags;
221*7c478bd9Sstevel@tonic-gate rt_msg->rtm_seq = ++rtmseq;
222*7c478bd9Sstevel@tonic-gate rlen = write(rtsock, rt_msg, RIPNG_RTM_MSGLEN);
223*7c478bd9Sstevel@tonic-gate if (rlen >= 0 && rlen < RIPNG_RTM_MSGLEN) {
224*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
225*7c478bd9Sstevel@tonic-gate "rtcmd: write to routing socket got only %d for rlen\n",
226*7c478bd9Sstevel@tonic-gate rlen);
227*7c478bd9Sstevel@tonic-gate }
228*7c478bd9Sstevel@tonic-gate return (rlen);
229*7c478bd9Sstevel@tonic-gate }
230*7c478bd9Sstevel@tonic-gate
231*7c478bd9Sstevel@tonic-gate void
rtadd(struct in6_addr * dst,struct in6_addr * gate,int prefix_length,int metric,int tag,boolean_t ifroute,struct interface * ifp)232*7c478bd9Sstevel@tonic-gate rtadd(struct in6_addr *dst, struct in6_addr *gate, int prefix_length,
233*7c478bd9Sstevel@tonic-gate int metric, int tag, boolean_t ifroute, struct interface *ifp)
234*7c478bd9Sstevel@tonic-gate {
235*7c478bd9Sstevel@tonic-gate struct rt_entry *rt;
236*7c478bd9Sstevel@tonic-gate struct rthash *rh;
237*7c478bd9Sstevel@tonic-gate uint_t hash;
238*7c478bd9Sstevel@tonic-gate struct in6_addr pdst;
239*7c478bd9Sstevel@tonic-gate int rlen;
240*7c478bd9Sstevel@tonic-gate
241*7c478bd9Sstevel@tonic-gate if (metric >= HOPCNT_INFINITY)
242*7c478bd9Sstevel@tonic-gate return;
243*7c478bd9Sstevel@tonic-gate
244*7c478bd9Sstevel@tonic-gate if (net_hashes[prefix_length] == NULL) {
245*7c478bd9Sstevel@tonic-gate struct rthash *trh;
246*7c478bd9Sstevel@tonic-gate
247*7c478bd9Sstevel@tonic-gate rh = (struct rthash *)
248*7c478bd9Sstevel@tonic-gate calloc(ROUTEHASHSIZ, sizeof (struct rt_entry));
249*7c478bd9Sstevel@tonic-gate if (rh == NULL)
250*7c478bd9Sstevel@tonic-gate return;
251*7c478bd9Sstevel@tonic-gate for (trh = rh; trh < &rh[ROUTEHASHSIZ]; trh++)
252*7c478bd9Sstevel@tonic-gate trh->rt_forw = trh->rt_back = (struct rt_entry *)trh;
253*7c478bd9Sstevel@tonic-gate net_hashes[prefix_length] = rh;
254*7c478bd9Sstevel@tonic-gate }
255*7c478bd9Sstevel@tonic-gate rtcreate_prefix(dst, &pdst, prefix_length);
256*7c478bd9Sstevel@tonic-gate
257*7c478bd9Sstevel@tonic-gate hash = rthash(&pdst, prefix_length);
258*7c478bd9Sstevel@tonic-gate rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK];
259*7c478bd9Sstevel@tonic-gate rt = (struct rt_entry *)malloc(sizeof (*rt));
260*7c478bd9Sstevel@tonic-gate if (rt == NULL) {
261*7c478bd9Sstevel@tonic-gate /*
262*7c478bd9Sstevel@tonic-gate * In the event of an allocation failure, log the error and
263*7c478bd9Sstevel@tonic-gate * continue since on the next update another attempt will be
264*7c478bd9Sstevel@tonic-gate * made.
265*7c478bd9Sstevel@tonic-gate */
266*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rtadd: malloc: %m");
267*7c478bd9Sstevel@tonic-gate return;
268*7c478bd9Sstevel@tonic-gate }
269*7c478bd9Sstevel@tonic-gate rt->rt_hash = hash;
270*7c478bd9Sstevel@tonic-gate rt->rt_dst = pdst;
271*7c478bd9Sstevel@tonic-gate rt->rt_prefix_length = prefix_length;
272*7c478bd9Sstevel@tonic-gate rt->rt_router = *gate;
273*7c478bd9Sstevel@tonic-gate rt->rt_metric = metric;
274*7c478bd9Sstevel@tonic-gate rt->rt_tag = tag;
275*7c478bd9Sstevel@tonic-gate rt->rt_timer = 0;
276*7c478bd9Sstevel@tonic-gate rt->rt_flags = RTF_UP;
277*7c478bd9Sstevel@tonic-gate if (prefix_length == IPV6_ABITS)
278*7c478bd9Sstevel@tonic-gate rt->rt_flags |= RTF_HOST;
279*7c478bd9Sstevel@tonic-gate rt->rt_state = RTS_CHANGED;
280*7c478bd9Sstevel@tonic-gate if (ifroute) {
281*7c478bd9Sstevel@tonic-gate rt->rt_state |= RTS_INTERFACE;
282*7c478bd9Sstevel@tonic-gate if (ifp->int_flags & RIP6_IFF_PRIVATE)
283*7c478bd9Sstevel@tonic-gate rt->rt_state |= RTS_PRIVATE;
284*7c478bd9Sstevel@tonic-gate } else {
285*7c478bd9Sstevel@tonic-gate rt->rt_flags |= RTF_GATEWAY;
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate rt->rt_ifp = ifp;
288*7c478bd9Sstevel@tonic-gate
289*7c478bd9Sstevel@tonic-gate insque(rt, rh);
290*7c478bd9Sstevel@tonic-gate TRACE_ACTION("ADD", rt);
291*7c478bd9Sstevel@tonic-gate /*
292*7c478bd9Sstevel@tonic-gate * If the RTM_ADD fails because the gateway is unreachable
293*7c478bd9Sstevel@tonic-gate * from this host, discard the entry. This should never
294*7c478bd9Sstevel@tonic-gate * happen.
295*7c478bd9Sstevel@tonic-gate */
296*7c478bd9Sstevel@tonic-gate if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
297*7c478bd9Sstevel@tonic-gate rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
298*7c478bd9Sstevel@tonic-gate prefix_length, ifp->int_name, rt->rt_flags);
299*7c478bd9Sstevel@tonic-gate if (rlen < 0) {
300*7c478bd9Sstevel@tonic-gate if (errno != EEXIST) {
301*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rtadd: RTM_ADD: %m");
302*7c478bd9Sstevel@tonic-gate log_single(LOG_ERR, rt);
303*7c478bd9Sstevel@tonic-gate }
304*7c478bd9Sstevel@tonic-gate if (errno == ENETUNREACH) {
305*7c478bd9Sstevel@tonic-gate TRACE_ACTION("DELETE", rt);
306*7c478bd9Sstevel@tonic-gate remque(rt);
307*7c478bd9Sstevel@tonic-gate free((char *)rt);
308*7c478bd9Sstevel@tonic-gate }
309*7c478bd9Sstevel@tonic-gate } else if (rlen < RIPNG_RTM_MSGLEN) {
310*7c478bd9Sstevel@tonic-gate log_single(LOG_ERR, rt);
311*7c478bd9Sstevel@tonic-gate }
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate }
314*7c478bd9Sstevel@tonic-gate
315*7c478bd9Sstevel@tonic-gate /*
316*7c478bd9Sstevel@tonic-gate * Handle the case when the metric changes but the gateway is the same (or the
317*7c478bd9Sstevel@tonic-gate * interface index associated with the gateway changes), or when both gateway
318*7c478bd9Sstevel@tonic-gate * and metric changes, or when only the gateway changes but the existing route
319*7c478bd9Sstevel@tonic-gate * is more than one-half of EXPIRE_TIME in age. Note that routes with metric >=
320*7c478bd9Sstevel@tonic-gate * HOPCNT_INFINITY are not in the kernel.
321*7c478bd9Sstevel@tonic-gate */
322*7c478bd9Sstevel@tonic-gate void
rtchange(struct rt_entry * rt,struct in6_addr * gate,short metric,struct interface * ifp)323*7c478bd9Sstevel@tonic-gate rtchange(struct rt_entry *rt, struct in6_addr *gate, short metric,
324*7c478bd9Sstevel@tonic-gate struct interface *ifp)
325*7c478bd9Sstevel@tonic-gate {
326*7c478bd9Sstevel@tonic-gate boolean_t dokern = _B_FALSE;
327*7c478bd9Sstevel@tonic-gate boolean_t dokerndelete;
328*7c478bd9Sstevel@tonic-gate boolean_t metricchanged = _B_FALSE;
329*7c478bd9Sstevel@tonic-gate int oldmetric;
330*7c478bd9Sstevel@tonic-gate struct rt_entry oldroute;
331*7c478bd9Sstevel@tonic-gate int rlen;
332*7c478bd9Sstevel@tonic-gate
333*7c478bd9Sstevel@tonic-gate if (metric >= HOPCNT_INFINITY) {
334*7c478bd9Sstevel@tonic-gate rtdown(rt);
335*7c478bd9Sstevel@tonic-gate return;
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate
338*7c478bd9Sstevel@tonic-gate if (!IN6_ARE_ADDR_EQUAL(&rt->rt_router, gate) || rt->rt_ifp != ifp)
339*7c478bd9Sstevel@tonic-gate dokern = _B_TRUE;
340*7c478bd9Sstevel@tonic-gate oldmetric = rt->rt_metric;
341*7c478bd9Sstevel@tonic-gate if (oldmetric >= HOPCNT_INFINITY)
342*7c478bd9Sstevel@tonic-gate dokerndelete = _B_FALSE;
343*7c478bd9Sstevel@tonic-gate else
344*7c478bd9Sstevel@tonic-gate dokerndelete = dokern;
345*7c478bd9Sstevel@tonic-gate if (metric != rt->rt_metric)
346*7c478bd9Sstevel@tonic-gate metricchanged = _B_TRUE;
347*7c478bd9Sstevel@tonic-gate rt->rt_timer = 0;
348*7c478bd9Sstevel@tonic-gate if (dokern || metricchanged) {
349*7c478bd9Sstevel@tonic-gate TRACE_ACTION("CHANGE FROM", rt);
350*7c478bd9Sstevel@tonic-gate if ((rt->rt_state & RTS_INTERFACE) && metric != 0) {
351*7c478bd9Sstevel@tonic-gate rt->rt_state &= ~RTS_INTERFACE;
352*7c478bd9Sstevel@tonic-gate if (rt->rt_ifp != NULL) {
353*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
354*7c478bd9Sstevel@tonic-gate "rtchange: changing route from "
355*7c478bd9Sstevel@tonic-gate "interface %s (timed out)",
356*7c478bd9Sstevel@tonic-gate (rt->rt_ifp->int_name != NULL) ?
357*7c478bd9Sstevel@tonic-gate rt->rt_ifp->int_name : "(noname)");
358*7c478bd9Sstevel@tonic-gate } else {
359*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
360*7c478bd9Sstevel@tonic-gate "rtchange: "
361*7c478bd9Sstevel@tonic-gate "changing route no interface for route");
362*7c478bd9Sstevel@tonic-gate }
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate if (dokern) {
365*7c478bd9Sstevel@tonic-gate oldroute = *rt;
366*7c478bd9Sstevel@tonic-gate rt->rt_router = *gate;
367*7c478bd9Sstevel@tonic-gate rt->rt_ifp = ifp;
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate rt->rt_metric = metric;
370*7c478bd9Sstevel@tonic-gate if (!(rt->rt_state & RTS_INTERFACE))
371*7c478bd9Sstevel@tonic-gate rt->rt_flags |= RTF_GATEWAY;
372*7c478bd9Sstevel@tonic-gate else
373*7c478bd9Sstevel@tonic-gate rt->rt_flags &= ~RTF_GATEWAY;
374*7c478bd9Sstevel@tonic-gate rt->rt_state |= RTS_CHANGED;
375*7c478bd9Sstevel@tonic-gate TRACE_ACTION("CHANGE TO", rt);
376*7c478bd9Sstevel@tonic-gate }
377*7c478bd9Sstevel@tonic-gate if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
378*7c478bd9Sstevel@tonic-gate if (dokerndelete) {
379*7c478bd9Sstevel@tonic-gate rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
380*7c478bd9Sstevel@tonic-gate rt->rt_prefix_length, rt->rt_ifp->int_name,
381*7c478bd9Sstevel@tonic-gate rt->rt_flags);
382*7c478bd9Sstevel@tonic-gate if (rlen < 0) {
383*7c478bd9Sstevel@tonic-gate if (errno != EEXIST) {
384*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
385*7c478bd9Sstevel@tonic-gate "rtchange: RTM_ADD: %m");
386*7c478bd9Sstevel@tonic-gate log_change(LOG_ERR, rt,
387*7c478bd9Sstevel@tonic-gate (struct rt_entry *)&oldroute);
388*7c478bd9Sstevel@tonic-gate }
389*7c478bd9Sstevel@tonic-gate } else if (rlen < RIPNG_RTM_MSGLEN) {
390*7c478bd9Sstevel@tonic-gate log_change(LOG_ERR, rt,
391*7c478bd9Sstevel@tonic-gate (struct rt_entry *)&oldroute);
392*7c478bd9Sstevel@tonic-gate }
393*7c478bd9Sstevel@tonic-gate
394*7c478bd9Sstevel@tonic-gate rlen = rtcmd(RTM_DELETE, &oldroute.rt_dst,
395*7c478bd9Sstevel@tonic-gate &oldroute.rt_router, oldroute.rt_prefix_length,
396*7c478bd9Sstevel@tonic-gate oldroute.rt_ifp->int_name, oldroute.rt_flags);
397*7c478bd9Sstevel@tonic-gate if (rlen < 0) {
398*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rtchange: RTM_DELETE: %m");
399*7c478bd9Sstevel@tonic-gate log_change(LOG_ERR, rt,
400*7c478bd9Sstevel@tonic-gate (struct rt_entry *)&oldroute);
401*7c478bd9Sstevel@tonic-gate } else if (rlen < RIPNG_RTM_MSGLEN) {
402*7c478bd9Sstevel@tonic-gate log_change(LOG_ERR, rt,
403*7c478bd9Sstevel@tonic-gate (struct rt_entry *)&oldroute);
404*7c478bd9Sstevel@tonic-gate }
405*7c478bd9Sstevel@tonic-gate } else if (dokern || oldmetric >= HOPCNT_INFINITY) {
406*7c478bd9Sstevel@tonic-gate rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
407*7c478bd9Sstevel@tonic-gate rt->rt_prefix_length, ifp->int_name, rt->rt_flags);
408*7c478bd9Sstevel@tonic-gate if (rlen < 0 && errno != EEXIST) {
409*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rtchange: RTM_ADD: %m");
410*7c478bd9Sstevel@tonic-gate log_change(LOG_ERR, rt,
411*7c478bd9Sstevel@tonic-gate (struct rt_entry *)&oldroute);
412*7c478bd9Sstevel@tonic-gate } else if (rlen < RIPNG_RTM_MSGLEN) {
413*7c478bd9Sstevel@tonic-gate log_change(LOG_ERR, rt,
414*7c478bd9Sstevel@tonic-gate (struct rt_entry *)&oldroute);
415*7c478bd9Sstevel@tonic-gate }
416*7c478bd9Sstevel@tonic-gate }
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate }
419*7c478bd9Sstevel@tonic-gate
420*7c478bd9Sstevel@tonic-gate void
rtdown(struct rt_entry * rt)421*7c478bd9Sstevel@tonic-gate rtdown(struct rt_entry *rt)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate int rlen;
424*7c478bd9Sstevel@tonic-gate
425*7c478bd9Sstevel@tonic-gate if (rt->rt_metric != HOPCNT_INFINITY) {
426*7c478bd9Sstevel@tonic-gate TRACE_ACTION("DELETE", rt);
427*7c478bd9Sstevel@tonic-gate if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
428*7c478bd9Sstevel@tonic-gate rlen = rtcmd(RTM_DELETE, &rt->rt_dst,
429*7c478bd9Sstevel@tonic-gate &rt->rt_router, rt->rt_prefix_length,
430*7c478bd9Sstevel@tonic-gate rt->rt_ifp->int_name, rt->rt_flags);
431*7c478bd9Sstevel@tonic-gate if (rlen < 0) {
432*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rtdown: RTM_DELETE: %m");
433*7c478bd9Sstevel@tonic-gate log_single(LOG_ERR, rt);
434*7c478bd9Sstevel@tonic-gate } else if (rlen < RIPNG_RTM_MSGLEN) {
435*7c478bd9Sstevel@tonic-gate log_single(LOG_ERR, rt);
436*7c478bd9Sstevel@tonic-gate }
437*7c478bd9Sstevel@tonic-gate }
438*7c478bd9Sstevel@tonic-gate rt->rt_metric = HOPCNT_INFINITY;
439*7c478bd9Sstevel@tonic-gate rt->rt_state |= RTS_CHANGED;
440*7c478bd9Sstevel@tonic-gate }
441*7c478bd9Sstevel@tonic-gate if (rt->rt_timer < EXPIRE_TIME)
442*7c478bd9Sstevel@tonic-gate rt->rt_timer = EXPIRE_TIME;
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate
445*7c478bd9Sstevel@tonic-gate void
rtdelete(struct rt_entry * rt)446*7c478bd9Sstevel@tonic-gate rtdelete(struct rt_entry *rt)
447*7c478bd9Sstevel@tonic-gate {
448*7c478bd9Sstevel@tonic-gate
449*7c478bd9Sstevel@tonic-gate if (rt->rt_state & RTS_INTERFACE) {
450*7c478bd9Sstevel@tonic-gate if (rt->rt_ifp != NULL) {
451*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
452*7c478bd9Sstevel@tonic-gate "rtdelete: "
453*7c478bd9Sstevel@tonic-gate "deleting route to interface %s (timed out)",
454*7c478bd9Sstevel@tonic-gate (rt->rt_ifp->int_name != NULL) ?
455*7c478bd9Sstevel@tonic-gate rt->rt_ifp->int_name : "(noname)");
456*7c478bd9Sstevel@tonic-gate log_single(LOG_ERR, rt);
457*7c478bd9Sstevel@tonic-gate }
458*7c478bd9Sstevel@tonic-gate }
459*7c478bd9Sstevel@tonic-gate rtdown(rt);
460*7c478bd9Sstevel@tonic-gate remque(rt);
461*7c478bd9Sstevel@tonic-gate free((char *)rt);
462*7c478bd9Sstevel@tonic-gate }
463*7c478bd9Sstevel@tonic-gate
464*7c478bd9Sstevel@tonic-gate /*
465*7c478bd9Sstevel@tonic-gate * Mark all the routes heard off a particular interface "down". Unlike the
466*7c478bd9Sstevel@tonic-gate * routes managed by in.routed, all of these routes have an interface associated
467*7c478bd9Sstevel@tonic-gate * with them.
468*7c478bd9Sstevel@tonic-gate */
469*7c478bd9Sstevel@tonic-gate void
rtpurgeif(struct interface * ifp)470*7c478bd9Sstevel@tonic-gate rtpurgeif(struct interface *ifp)
471*7c478bd9Sstevel@tonic-gate {
472*7c478bd9Sstevel@tonic-gate struct rthash *rh;
473*7c478bd9Sstevel@tonic-gate struct rt_entry *rt;
474*7c478bd9Sstevel@tonic-gate int i;
475*7c478bd9Sstevel@tonic-gate
476*7c478bd9Sstevel@tonic-gate for (i = IPV6_ABITS; i >= 0; i--) {
477*7c478bd9Sstevel@tonic-gate if (net_hashes[i] == NULL)
478*7c478bd9Sstevel@tonic-gate continue;
479*7c478bd9Sstevel@tonic-gate
480*7c478bd9Sstevel@tonic-gate for (rh = net_hashes[i];
481*7c478bd9Sstevel@tonic-gate rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
482*7c478bd9Sstevel@tonic-gate for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
483*7c478bd9Sstevel@tonic-gate rt = rt->rt_forw) {
484*7c478bd9Sstevel@tonic-gate if (rt->rt_ifp == ifp) {
485*7c478bd9Sstevel@tonic-gate rtdown(rt);
486*7c478bd9Sstevel@tonic-gate rt->rt_ifp = NULL;
487*7c478bd9Sstevel@tonic-gate rt->rt_state &= ~RTS_INTERFACE;
488*7c478bd9Sstevel@tonic-gate }
489*7c478bd9Sstevel@tonic-gate }
490*7c478bd9Sstevel@tonic-gate }
491*7c478bd9Sstevel@tonic-gate }
492*7c478bd9Sstevel@tonic-gate }
493*7c478bd9Sstevel@tonic-gate
494*7c478bd9Sstevel@tonic-gate /*
495*7c478bd9Sstevel@tonic-gate * Called when the subnetmask has changed on one or more interfaces.
496*7c478bd9Sstevel@tonic-gate * Re-evaluates all non-interface routes by doing a rtchange so that
497*7c478bd9Sstevel@tonic-gate * routes that were believed to be host routes before the netmask change
498*7c478bd9Sstevel@tonic-gate * can be converted to network routes and vice versa.
499*7c478bd9Sstevel@tonic-gate */
500*7c478bd9Sstevel@tonic-gate void
rtchangeall(void)501*7c478bd9Sstevel@tonic-gate rtchangeall(void)
502*7c478bd9Sstevel@tonic-gate {
503*7c478bd9Sstevel@tonic-gate struct rthash *rh;
504*7c478bd9Sstevel@tonic-gate struct rt_entry *rt;
505*7c478bd9Sstevel@tonic-gate int i;
506*7c478bd9Sstevel@tonic-gate
507*7c478bd9Sstevel@tonic-gate for (i = IPV6_ABITS; i >= 0; i--) {
508*7c478bd9Sstevel@tonic-gate if (net_hashes[i] == NULL)
509*7c478bd9Sstevel@tonic-gate continue;
510*7c478bd9Sstevel@tonic-gate
511*7c478bd9Sstevel@tonic-gate for (rh = net_hashes[i];
512*7c478bd9Sstevel@tonic-gate rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
513*7c478bd9Sstevel@tonic-gate for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
514*7c478bd9Sstevel@tonic-gate rt = rt->rt_forw) {
515*7c478bd9Sstevel@tonic-gate if ((rt->rt_state & RTS_INTERFACE) == 0) {
516*7c478bd9Sstevel@tonic-gate rtchange(rt, &rt->rt_router,
517*7c478bd9Sstevel@tonic-gate rt->rt_metric, rt->rt_ifp);
518*7c478bd9Sstevel@tonic-gate }
519*7c478bd9Sstevel@tonic-gate }
520*7c478bd9Sstevel@tonic-gate }
521*7c478bd9Sstevel@tonic-gate }
522*7c478bd9Sstevel@tonic-gate }
523*7c478bd9Sstevel@tonic-gate
524*7c478bd9Sstevel@tonic-gate static void
rtdumpentry(FILE * fp,struct rt_entry * rt)525*7c478bd9Sstevel@tonic-gate rtdumpentry(FILE *fp, struct rt_entry *rt)
526*7c478bd9Sstevel@tonic-gate {
527*7c478bd9Sstevel@tonic-gate char buf1[INET6_ADDRSTRLEN];
528*7c478bd9Sstevel@tonic-gate static struct bits {
529*7c478bd9Sstevel@tonic-gate ulong_t t_bits;
530*7c478bd9Sstevel@tonic-gate char *t_name;
531*7c478bd9Sstevel@tonic-gate } flagbits[] = {
532*7c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */
533*7c478bd9Sstevel@tonic-gate { RTF_UP, "UP" },
534*7c478bd9Sstevel@tonic-gate { RTF_GATEWAY, "GATEWAY" },
535*7c478bd9Sstevel@tonic-gate { RTF_HOST, "HOST" },
536*7c478bd9Sstevel@tonic-gate { 0, NULL }
537*7c478bd9Sstevel@tonic-gate /* END CSTYLED */
538*7c478bd9Sstevel@tonic-gate }, statebits[] = {
539*7c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */
540*7c478bd9Sstevel@tonic-gate { RTS_INTERFACE, "INTERFACE" },
541*7c478bd9Sstevel@tonic-gate { RTS_CHANGED, "CHANGED" },
542*7c478bd9Sstevel@tonic-gate { RTS_PRIVATE, "PRIVATE" },
543*7c478bd9Sstevel@tonic-gate { 0, NULL }
544*7c478bd9Sstevel@tonic-gate /* END CSTYLED */
545*7c478bd9Sstevel@tonic-gate };
546*7c478bd9Sstevel@tonic-gate struct bits *p;
547*7c478bd9Sstevel@tonic-gate boolean_t first;
548*7c478bd9Sstevel@tonic-gate char c;
549*7c478bd9Sstevel@tonic-gate
550*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "prefix %s/%d ",
551*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1)),
552*7c478bd9Sstevel@tonic-gate rt->rt_prefix_length);
553*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "via %s metric %d timer %d",
554*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1, sizeof (buf1)),
555*7c478bd9Sstevel@tonic-gate rt->rt_metric, rt->rt_timer);
556*7c478bd9Sstevel@tonic-gate if (rt->rt_ifp != NULL) {
557*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, " if %s",
558*7c478bd9Sstevel@tonic-gate (rt->rt_ifp->int_name != NULL) ?
559*7c478bd9Sstevel@tonic-gate rt->rt_ifp->int_name : "(noname)");
560*7c478bd9Sstevel@tonic-gate }
561*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, " state");
562*7c478bd9Sstevel@tonic-gate c = ' ';
563*7c478bd9Sstevel@tonic-gate for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) {
564*7c478bd9Sstevel@tonic-gate if ((rt->rt_state & p->t_bits) == 0)
565*7c478bd9Sstevel@tonic-gate continue;
566*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%c%s", c, p->t_name);
567*7c478bd9Sstevel@tonic-gate if (first) {
568*7c478bd9Sstevel@tonic-gate c = '|';
569*7c478bd9Sstevel@tonic-gate first = _B_FALSE;
570*7c478bd9Sstevel@tonic-gate }
571*7c478bd9Sstevel@tonic-gate }
572*7c478bd9Sstevel@tonic-gate if (first)
573*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, " 0");
574*7c478bd9Sstevel@tonic-gate if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) {
575*7c478bd9Sstevel@tonic-gate c = ' ';
576*7c478bd9Sstevel@tonic-gate for (first = _B_TRUE, p = flagbits; p->t_bits > 0; p++) {
577*7c478bd9Sstevel@tonic-gate if ((rt->rt_flags & p->t_bits) == 0)
578*7c478bd9Sstevel@tonic-gate continue;
579*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%c%s", c, p->t_name);
580*7c478bd9Sstevel@tonic-gate if (first) {
581*7c478bd9Sstevel@tonic-gate c = '|';
582*7c478bd9Sstevel@tonic-gate first = _B_FALSE;
583*7c478bd9Sstevel@tonic-gate }
584*7c478bd9Sstevel@tonic-gate }
585*7c478bd9Sstevel@tonic-gate }
586*7c478bd9Sstevel@tonic-gate (void) putc('\n', fp);
587*7c478bd9Sstevel@tonic-gate (void) fflush(fp);
588*7c478bd9Sstevel@tonic-gate }
589*7c478bd9Sstevel@tonic-gate
590*7c478bd9Sstevel@tonic-gate static void
rtdump2(FILE * fp)591*7c478bd9Sstevel@tonic-gate rtdump2(FILE *fp)
592*7c478bd9Sstevel@tonic-gate {
593*7c478bd9Sstevel@tonic-gate struct rthash *rh;
594*7c478bd9Sstevel@tonic-gate struct rt_entry *rt;
595*7c478bd9Sstevel@tonic-gate int i;
596*7c478bd9Sstevel@tonic-gate
597*7c478bd9Sstevel@tonic-gate for (i = IPV6_ABITS; i >= 0; i--) {
598*7c478bd9Sstevel@tonic-gate if (net_hashes[i] == NULL)
599*7c478bd9Sstevel@tonic-gate continue;
600*7c478bd9Sstevel@tonic-gate
601*7c478bd9Sstevel@tonic-gate for (rh = net_hashes[i];
602*7c478bd9Sstevel@tonic-gate rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
603*7c478bd9Sstevel@tonic-gate for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
604*7c478bd9Sstevel@tonic-gate rt = rt->rt_forw) {
605*7c478bd9Sstevel@tonic-gate rtdumpentry(fp, rt);
606*7c478bd9Sstevel@tonic-gate }
607*7c478bd9Sstevel@tonic-gate }
608*7c478bd9Sstevel@tonic-gate }
609*7c478bd9Sstevel@tonic-gate }
610*7c478bd9Sstevel@tonic-gate
611*7c478bd9Sstevel@tonic-gate void
rtdump(void)612*7c478bd9Sstevel@tonic-gate rtdump(void)
613*7c478bd9Sstevel@tonic-gate {
614*7c478bd9Sstevel@tonic-gate if (ftrace != NULL)
615*7c478bd9Sstevel@tonic-gate rtdump2(ftrace);
616*7c478bd9Sstevel@tonic-gate else
617*7c478bd9Sstevel@tonic-gate rtdump2(stderr);
618*7c478bd9Sstevel@tonic-gate }
619*7c478bd9Sstevel@tonic-gate
620*7c478bd9Sstevel@tonic-gate /*
621*7c478bd9Sstevel@tonic-gate * Create a routing socket for sending RTM_ADD and RTM_DELETE messages and
622*7c478bd9Sstevel@tonic-gate * initialize the routing socket message header and as much of the sockaddrs
623*7c478bd9Sstevel@tonic-gate * as possible.
624*7c478bd9Sstevel@tonic-gate */
625*7c478bd9Sstevel@tonic-gate void
setup_rtsock(void)626*7c478bd9Sstevel@tonic-gate setup_rtsock(void)
627*7c478bd9Sstevel@tonic-gate {
628*7c478bd9Sstevel@tonic-gate char *cp;
629*7c478bd9Sstevel@tonic-gate int off = 0;
630*7c478bd9Sstevel@tonic-gate
631*7c478bd9Sstevel@tonic-gate rtsock = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
632*7c478bd9Sstevel@tonic-gate if (rtsock < 0) {
633*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setup_rtsock: socket: %m");
634*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
635*7c478bd9Sstevel@tonic-gate }
636*7c478bd9Sstevel@tonic-gate
637*7c478bd9Sstevel@tonic-gate /* We don't want to listen to our own messages */
638*7c478bd9Sstevel@tonic-gate if (setsockopt(rtsock, SOL_SOCKET, SO_USELOOPBACK, (char *)&off,
639*7c478bd9Sstevel@tonic-gate sizeof (off)) < 0) {
640*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setup_rtsock: setsockopt: SO_USELOOPBACK: %m");
641*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
642*7c478bd9Sstevel@tonic-gate }
643*7c478bd9Sstevel@tonic-gate
644*7c478bd9Sstevel@tonic-gate /*
645*7c478bd9Sstevel@tonic-gate * Allocate storage for the routing socket message.
646*7c478bd9Sstevel@tonic-gate */
647*7c478bd9Sstevel@tonic-gate rt_msg = (struct rt_msghdr *)malloc(RIPNG_RTM_MSGLEN);
648*7c478bd9Sstevel@tonic-gate if (rt_msg == NULL) {
649*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setup_rtsock: malloc: %m");
650*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
651*7c478bd9Sstevel@tonic-gate }
652*7c478bd9Sstevel@tonic-gate
653*7c478bd9Sstevel@tonic-gate /*
654*7c478bd9Sstevel@tonic-gate * Initialize the routing socket message by zero-filling it and then
655*7c478bd9Sstevel@tonic-gate * setting the fields where are constant through the lifetime of the
656*7c478bd9Sstevel@tonic-gate * process.
657*7c478bd9Sstevel@tonic-gate */
658*7c478bd9Sstevel@tonic-gate bzero(rt_msg, RIPNG_RTM_MSGLEN);
659*7c478bd9Sstevel@tonic-gate rt_msg->rtm_msglen = RIPNG_RTM_MSGLEN;
660*7c478bd9Sstevel@tonic-gate rt_msg->rtm_version = RTM_VERSION;
661*7c478bd9Sstevel@tonic-gate rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP;
662*7c478bd9Sstevel@tonic-gate rt_msg->rtm_pid = getpid();
663*7c478bd9Sstevel@tonic-gate if (rt_msg->rtm_pid < 0) {
664*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setup_rtsock: getpid: %m");
665*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
666*7c478bd9Sstevel@tonic-gate }
667*7c478bd9Sstevel@tonic-gate
668*7c478bd9Sstevel@tonic-gate /*
669*7c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_DST sockaddr.
670*7c478bd9Sstevel@tonic-gate */
671*7c478bd9Sstevel@tonic-gate cp = (char *)rt_msg + sizeof (struct rt_msghdr);
672*7c478bd9Sstevel@tonic-gate rta_dst = (struct sockaddr_in6 *)cp;
673*7c478bd9Sstevel@tonic-gate rta_dst->sin6_family = AF_INET6;
674*7c478bd9Sstevel@tonic-gate
675*7c478bd9Sstevel@tonic-gate /*
676*7c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_GATEWAY sockaddr.
677*7c478bd9Sstevel@tonic-gate */
678*7c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6);
679*7c478bd9Sstevel@tonic-gate rta_gateway = (struct sockaddr_in6 *)cp;
680*7c478bd9Sstevel@tonic-gate rta_gateway->sin6_family = AF_INET6;
681*7c478bd9Sstevel@tonic-gate
682*7c478bd9Sstevel@tonic-gate /*
683*7c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_NETMASK sockaddr.
684*7c478bd9Sstevel@tonic-gate */
685*7c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6);
686*7c478bd9Sstevel@tonic-gate rta_netmask = (struct sockaddr_in6 *)cp;
687*7c478bd9Sstevel@tonic-gate rta_netmask->sin6_family = AF_INET6;
688*7c478bd9Sstevel@tonic-gate
689*7c478bd9Sstevel@tonic-gate /*
690*7c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_IFP sockaddr.
691*7c478bd9Sstevel@tonic-gate */
692*7c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6);
693*7c478bd9Sstevel@tonic-gate rta_ifp = (struct sockaddr_dl *)cp;
694*7c478bd9Sstevel@tonic-gate rta_ifp->sdl_family = AF_LINK;
695*7c478bd9Sstevel@tonic-gate }
696