This source file includes following definitions.
- in6_selectsrc
- selectroute
- in6_selectroute
- in6_selecthlim
- in6_embedscope
- in6_recoverscope
- in6_clearscope
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/malloc.h>
67 #include <sys/mbuf.h>
68 #include <sys/protosw.h>
69 #include <sys/socket.h>
70 #include <sys/socketvar.h>
71 #include <sys/ioctl.h>
72 #include <sys/errno.h>
73 #include <sys/time.h>
74 #include <sys/proc.h>
75
76 #include <net/if.h>
77 #include <net/route.h>
78
79 #include <netinet/in.h>
80 #include <netinet/in_var.h>
81 #include <netinet/in_systm.h>
82 #include <netinet/ip.h>
83 #include <netinet/in_pcb.h>
84 #include <netinet6/in6_var.h>
85 #include <netinet/ip6.h>
86 #include <netinet6/ip6_var.h>
87 #include <netinet6/nd6.h>
88
89 static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
90 struct ip6_moptions *, struct route_in6 *, struct ifnet **,
91 struct rtentry **, int);
92
93
94
95
96
97
98
99 struct in6_addr *
100 in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
101 struct sockaddr_in6 *dstsock;
102 struct ip6_pktopts *opts;
103 struct ip6_moptions *mopts;
104 struct route_in6 *ro;
105 struct in6_addr *laddr;
106 int *errorp;
107 {
108 struct in6_addr *dst;
109 struct in6_ifaddr *ia6 = 0;
110 struct in6_pktinfo *pi = NULL;
111
112 dst = &dstsock->sin6_addr;
113 *errorp = 0;
114
115
116
117
118
119 if (opts && (pi = opts->ip6po_pktinfo) &&
120 !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
121 return (&pi->ipi6_addr);
122
123
124
125
126
127 if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
128 return (laddr);
129
130
131
132
133
134
135 if (pi && pi->ipi6_ifindex) {
136
137 ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
138 dst);
139 if (ia6 == 0) {
140 *errorp = EADDRNOTAVAIL;
141 return (0);
142 }
143 return (&satosin6(&ia6->ia_addr)->sin6_addr);
144 }
145
146
147
148
149
150
151
152
153
154
155 if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
156 IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
157
158
159
160
161 if (dstsock->sin6_scope_id < 0 ||
162 if_indexlim <= dstsock->sin6_scope_id ||
163 !ifindex2ifnet[dstsock->sin6_scope_id]) {
164 *errorp = ENXIO;
165 return (0);
166 }
167 ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
168 dst);
169 if (ia6 == 0) {
170 *errorp = EADDRNOTAVAIL;
171 return (0);
172 }
173 return (&satosin6(&ia6->ia_addr)->sin6_addr);
174 }
175
176
177
178
179
180
181
182
183 if (IN6_IS_ADDR_MULTICAST(dst)) {
184 struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
185
186 if (!ifp && dstsock->sin6_scope_id)
187 ifp = ifindex2ifnet[htons(dstsock->sin6_scope_id)];
188
189 if (ifp) {
190 ia6 = in6_ifawithscope(ifp, dst);
191 if (ia6 == 0) {
192 *errorp = EADDRNOTAVAIL;
193 return (0);
194 }
195 return (&satosin6(&ia6->ia_addr)->sin6_addr);
196 }
197 }
198
199
200
201
202
203
204 {
205 struct sockaddr_in6 *sin6_next;
206 struct rtentry *rt;
207
208 if (opts && opts->ip6po_nexthop) {
209 sin6_next = satosin6(opts->ip6po_nexthop);
210 rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
211 if (rt) {
212 ia6 = in6_ifawithscope(rt->rt_ifp, dst);
213 if (ia6 == 0)
214 ia6 = ifatoia6(rt->rt_ifa);
215 }
216 if (ia6 == 0) {
217 *errorp = EADDRNOTAVAIL;
218 return (0);
219 }
220 return (&satosin6(&ia6->ia_addr)->sin6_addr);
221 }
222 }
223
224
225
226
227
228 if (ro) {
229 if (ro->ro_rt &&
230 !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
231 RTFREE(ro->ro_rt);
232 ro->ro_rt = (struct rtentry *)0;
233 }
234 if (ro->ro_rt == (struct rtentry *)0 ||
235 ro->ro_rt->rt_ifp == (struct ifnet *)0) {
236 struct sockaddr_in6 *sa6;
237
238
239 bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
240 sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
241 sa6->sin6_family = AF_INET6;
242 sa6->sin6_len = sizeof(struct sockaddr_in6);
243 sa6->sin6_addr = *dst;
244 sa6->sin6_scope_id = dstsock->sin6_scope_id;
245 if (IN6_IS_ADDR_MULTICAST(dst)) {
246 ro->ro_rt = rtalloc1(&((struct route *)ro)
247 ->ro_dst, 0, 0);
248 } else {
249 rtalloc_mpath((struct route *)ro, NULL, 0);
250 }
251 }
252
253
254
255
256
257
258
259
260 if (ro->ro_rt) {
261 ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
262 if (ia6 == 0)
263 ia6 = ifatoia6(ro->ro_rt->rt_ifa);
264 }
265 #if 0
266
267
268
269
270
271 if (ia6 == 0) {
272 struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
273
274 sin6->sin6_addr = *dst;
275
276 ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
277 if (ia6 == 0)
278 ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
279 if (ia6 == 0)
280 return (0);
281 return (&satosin6(&ia6->ia_addr)->sin6_addr);
282 }
283 #endif
284 if (ia6 == 0) {
285 *errorp = EHOSTUNREACH;
286 return (0);
287 }
288 return (&satosin6(&ia6->ia_addr)->sin6_addr);
289 }
290
291 *errorp = EADDRNOTAVAIL;
292 return (0);
293 }
294
295 static int
296 selectroute(dstsock, opts, mopts, ro, retifp, retrt, norouteok)
297 struct sockaddr_in6 *dstsock;
298 struct ip6_pktopts *opts;
299 struct ip6_moptions *mopts;
300 struct route_in6 *ro;
301 struct ifnet **retifp;
302 struct rtentry **retrt;
303 int norouteok;
304 {
305 int error = 0;
306 struct ifnet *ifp = NULL;
307 struct rtentry *rt = NULL;
308 struct sockaddr_in6 *sin6_next;
309 struct in6_pktinfo *pi = NULL;
310 struct in6_addr *dst;
311
312 dst = &dstsock->sin6_addr;
313
314 #if 0
315 if (dstsock->sin6_addr.s6_addr32[0] == 0 &&
316 dstsock->sin6_addr.s6_addr32[1] == 0 &&
317 !IN6_IS_ADDR_LOOPBACK(&dstsock->sin6_addr)) {
318 printf("in6_selectroute: strange destination %s\n",
319 ip6_sprintf(&dstsock->sin6_addr));
320 } else {
321 printf("in6_selectroute: destination = %s%%%d\n",
322 ip6_sprintf(&dstsock->sin6_addr),
323 dstsock->sin6_scope_id);
324 }
325 #endif
326
327
328 if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
329
330 ifp = ifindex2ifnet[pi->ipi6_ifindex];
331 if (ifp != NULL &&
332 (norouteok || retrt == NULL ||
333 IN6_IS_ADDR_MULTICAST(dst))) {
334
335
336
337
338 goto done;
339 } else
340 goto getroute;
341 }
342
343
344
345
346
347 if (IN6_IS_ADDR_MULTICAST(dst) &&
348 mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {
349 goto done;
350 }
351
352 getroute:
353
354
355
356
357 if (opts && opts->ip6po_nexthop) {
358 struct route_in6 *ron;
359
360 sin6_next = satosin6(opts->ip6po_nexthop);
361
362
363 if (sin6_next->sin6_family != AF_INET6) {
364 error = EAFNOSUPPORT;
365 goto done;
366 }
367
368
369
370
371
372 ron = &opts->ip6po_nextroute;
373 if ((ron->ro_rt &&
374 (ron->ro_rt->rt_flags & (RTF_UP | RTF_GATEWAY)) !=
375 RTF_UP) ||
376 !IN6_ARE_ADDR_EQUAL(&satosin6(&ron->ro_dst)->sin6_addr,
377 &sin6_next->sin6_addr)) {
378 if (ron->ro_rt) {
379 RTFREE(ron->ro_rt);
380 ron->ro_rt = NULL;
381 }
382 *satosin6(&ron->ro_dst) = *sin6_next;
383 }
384 if (ron->ro_rt == NULL) {
385 rtalloc((struct route *)ron);
386 if (ron->ro_rt == NULL ||
387 (ron->ro_rt->rt_flags & RTF_GATEWAY)) {
388 if (ron->ro_rt) {
389 RTFREE(ron->ro_rt);
390 ron->ro_rt = NULL;
391 }
392 error = EHOSTUNREACH;
393 goto done;
394 }
395 }
396 if (!nd6_is_addr_neighbor(sin6_next, ron->ro_rt->rt_ifp)) {
397 RTFREE(ron->ro_rt);
398 ron->ro_rt = NULL;
399 error = EHOSTUNREACH;
400 goto done;
401 }
402 rt = ron->ro_rt;
403 ifp = rt->rt_ifp;
404
405
406
407
408
409
410 goto done;
411 }
412
413
414
415
416
417
418 if (ro) {
419 if (ro->ro_rt &&
420 (!(ro->ro_rt->rt_flags & RTF_UP) ||
421 ((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 ||
422 !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
423 dst))) {
424 RTFREE(ro->ro_rt);
425 ro->ro_rt = (struct rtentry *)NULL;
426 }
427 if (ro->ro_rt == (struct rtentry *)NULL) {
428 struct sockaddr_in6 *sa6;
429
430
431 bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
432 sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
433 *sa6 = *dstsock;
434 sa6->sin6_scope_id = 0;
435 rtalloc_mpath((struct route *)ro, NULL, 0);
436 }
437
438
439
440
441
442 if (opts && opts->ip6po_nexthop)
443 goto done;
444
445 if (ro->ro_rt) {
446 ifp = ro->ro_rt->rt_ifp;
447
448 if (ifp == NULL) {
449 RTFREE(ro->ro_rt);
450 ro->ro_rt = NULL;
451 }
452 }
453 if (ro->ro_rt == NULL)
454 error = EHOSTUNREACH;
455 rt = ro->ro_rt;
456
457
458
459
460
461
462
463
464 if (opts && opts->ip6po_pktinfo &&
465 opts->ip6po_pktinfo->ipi6_ifindex) {
466 if (!(ifp->if_flags & IFF_LOOPBACK) &&
467 ifp->if_index !=
468 opts->ip6po_pktinfo->ipi6_ifindex) {
469 error = EHOSTUNREACH;
470 goto done;
471 }
472 }
473 }
474
475 done:
476 if (ifp == NULL && rt == NULL) {
477
478
479
480
481 error = EHOSTUNREACH;
482 }
483 if (error == EHOSTUNREACH)
484 ip6stat.ip6s_noroute++;
485
486 if (retifp != NULL)
487 *retifp = ifp;
488 if (retrt != NULL)
489 *retrt = rt;
490
491 return (error);
492 }
493
494 int
495 in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt)
496 struct sockaddr_in6 *dstsock;
497 struct ip6_pktopts *opts;
498 struct ip6_moptions *mopts;
499 struct route_in6 *ro;
500 struct ifnet **retifp;
501 struct rtentry **retrt;
502 {
503
504 return (selectroute(dstsock, opts, mopts, ro, retifp, retrt, 0));
505 }
506
507
508
509
510
511
512
513
514 #define in6pcb inpcb
515 #define in6p_hops inp_hops
516 int
517 in6_selecthlim(in6p, ifp)
518 struct in6pcb *in6p;
519 struct ifnet *ifp;
520 {
521 if (in6p && in6p->in6p_hops >= 0)
522 return (in6p->in6p_hops);
523 else if (ifp)
524 return (ND_IFINFO(ifp)->chlim);
525 else
526 return (ip6_defhlim);
527 }
528 #undef in6pcb
529 #undef in6p_hops
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546 int
547 in6_embedscope(in6, sin6, in6p, ifpp)
548 struct in6_addr *in6;
549 const struct sockaddr_in6 *sin6;
550 struct inpcb *in6p;
551 #define in6p_outputopts inp_outputopts6
552 #define in6p_moptions inp_moptions6
553 struct ifnet **ifpp;
554 {
555 struct ifnet *ifp = NULL;
556 u_int32_t scopeid;
557
558 *in6 = sin6->sin6_addr;
559 scopeid = sin6->sin6_scope_id;
560 if (ifpp)
561 *ifpp = NULL;
562
563
564
565
566
567
568 if (IN6_IS_SCOPE_EMBED(in6)) {
569 struct in6_pktinfo *pi;
570
571
572
573
574
575 if (in6p && in6p->in6p_outputopts &&
576 (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
577 pi->ipi6_ifindex) {
578 ifp = ifindex2ifnet[pi->ipi6_ifindex];
579 in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
580 } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
581 in6p->in6p_moptions &&
582 in6p->in6p_moptions->im6o_multicast_ifp) {
583 ifp = in6p->in6p_moptions->im6o_multicast_ifp;
584 in6->s6_addr16[1] = htons(ifp->if_index);
585 } else if (scopeid) {
586
587 if (scopeid < 0 || if_indexlim <= scopeid ||
588 !ifindex2ifnet[scopeid])
589 return ENXIO;
590 ifp = ifindex2ifnet[scopeid];
591
592 in6->s6_addr16[1] = htons(scopeid & 0xffff);
593 }
594
595 if (ifpp)
596 *ifpp = ifp;
597 }
598
599 return 0;
600 }
601 #undef in6p_outputopts
602 #undef in6p_moptions
603
604
605
606
607
608
609
610
611 int
612 in6_recoverscope(sin6, in6, ifp)
613 struct sockaddr_in6 *sin6;
614 const struct in6_addr *in6;
615 struct ifnet *ifp;
616 {
617 u_int32_t scopeid;
618
619 sin6->sin6_addr = *in6;
620
621
622
623
624
625
626 sin6->sin6_scope_id = 0;
627 if (IN6_IS_SCOPE_EMBED(in6)) {
628
629
630
631 scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
632 if (scopeid) {
633
634 if (scopeid < 0 || if_indexlim <= scopeid ||
635 !ifindex2ifnet[scopeid])
636 return ENXIO;
637 if (ifp && ifp->if_index != scopeid)
638 return ENXIO;
639 sin6->sin6_addr.s6_addr16[1] = 0;
640 sin6->sin6_scope_id = scopeid;
641 }
642 }
643
644 return 0;
645 }
646
647
648
649
650 void
651 in6_clearscope(addr)
652 struct in6_addr *addr;
653 {
654 if (IN6_IS_SCOPE_EMBED(addr))
655 addr->s6_addr16[1] = 0;
656 }