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