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