source: EcnlProtoTool/trunk/asp3_dcre/tinet/netinet6/nd6_rtr.c@ 321

Last change on this file since 321 was 321, checked in by coas-nagasima, 7 years ago

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 41.0 KB
Line 
1/*
2 * TINET (TCP/IP Protocol Stack)
3 *
4 * Copyright (C) 2001-2009 by Dep. of Computer Science and Engineering
5 * Tomakomai National College of Technology, JAPAN
6 *
7 * 上記著作権者は,以下の (1)~(4) の条件か,Free Software Foundation
8 * によって公表されている GNU General Public License の Version 2 に記
9 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
10 * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
11 * 利用と呼ぶ)することを無償で許諾する.
12 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14 * スコード中に含まれていること.
15 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18 * の無保証規定を掲載すること.
19 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20 * 用できない形で再配布する場合には,次の条件を満たすこと.
21 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
22 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
23 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25 *
26 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
27 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
28 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
29 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
30 *
31 * @(#) $Id$
32 */
33
34/* $FreeBSD: src/sys/netinet6/nd6_rtr.c,v 1.11 2002/04/19 04:46:23 suz Exp $ */
35/* $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ */
36
37/*
38 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
39 * All rights reserved.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the project nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66#include <string.h>
67
68#ifdef TARGET_KERNEL_ASP
69
70#include <kernel.h>
71#include <sil.h>
72#include <t_syslog.h>
73#include "kernel_cfg.h"
74
75#endif /* of #ifdef TARGET_KERNEL_ASP */
76
77#ifdef TARGET_KERNEL_JSP
78
79#include <s_services.h>
80#include <t_services.h>
81#include "kernel_id.h"
82
83#endif /* of #ifdef TARGET_KERNEL_JSP */
84
85#include <tinet_defs.h>
86#include <tinet_config.h>
87
88#include <net/if.h>
89#include <net/if_ppp.h>
90#include <net/if_loop.h>
91#include <net/ethernet.h>
92#include <net/if_arp.h>
93#include <net/ppp_ipcp.h>
94#include <net/net.h>
95#include <net/net_var.h>
96#include <net/net_buf.h>
97#include <net/net_timer.h>
98#include <net/net_count.h>
99
100#include <netinet/in.h>
101#include <netinet/in_var.h>
102#include <netinet6/in6.h>
103#include <netinet6/in6_var.h>
104#include <netinet6/nd6.h>
105#include <netinet6/in6_ifattach.h>
106#include <netinet/ip6.h>
107#include <netinet/icmp6.h>
108#include <netinet6/ip6_var.h>
109
110#include <net/if6_var.h>
111
112/*
113 * 外部関数の定義
114 */
115
116extern const char *itron_strerror (ER ercd);
117
118#ifdef SUPPORT_INET6
119
120#if NUM_ND6_DEF_RTR_ENTRY > 0
121
122/*
123 * 全域変数
124 */
125
126SYSTIM nd6_base_reachable_time = ND6_DEF_REACHABLE_TIME; /* ルータから通知された値 */
127SYSTIM nd6_reachable_time = ND6_DEF_REACHABLE_TIME; /* ルータから通知された値の補正値 */
128SYSTIM nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; /* 到達可能状態の有効時間再計算間隔 */
129SYSTIM nd6_retrans_time = ND6_DEF_RETRANS_TIME; /* 近隣探索の送信間隔 */
130uint8_t ip6_defhlim = IPV6_DEFHLIM; /* ホップリミットの規定値 */
131
132/*
133 * 局所変数
134 */
135
136/*
137 * プレフィックス・リスト
138 */
139
140static T_ND6_PREFIX nd6_prefix[NUM_ND6_PREFIX_ENTRY];
141
142/*
143 * ディフォルトルータ・リスト
144 */
145
146static T_DEF_ROUTER nd6_def_router[NUM_ND6_DEF_RTR_ENTRY];
147static uint_t def_router_count = 0; /* リストにあるルータ数 */
148
149/*
150 * make_mask -- マップ用のマスクを生成する。
151 */
152
153static uint_t
154make_mask (int_t index)
155{
156 uint_t mask;
157 int_t ix;
158
159 /* マスクを生成する。*/
160 mask = 1;
161 for (ix = index; ix -- > 0; )
162 mask <<= 1;
163
164 return mask;
165 }
166
167/*
168 * find_pfxlist_reachable_router --
169 * 指定したプレフィックスを通知したルータがリンク上に存在するかチェックする。
170 */
171
172static T_DEF_ROUTER *
173find_pfxlist_reachable_router (T_ND6_PREFIX *pr)
174{
175 T_DEF_ROUTER *dr = NULL;
176 T_LLINFO_ND6 *ln;
177 uint_t mask;
178 int_t ix;
179
180 mask = 1;
181 for (ix = 0; ix < def_router_count; ix ++) {
182 if ((pr->routermap & mask) != 0) {
183 if ((ln = nd6_lookup(&nd6_def_router[ix].addr, false)) != NULL &&
184 ND6_IS_LLINFO_PROBREACH(ln))
185 return dr;
186 }
187 mask <<= 1;
188 }
189 return NULL;
190 }
191
192/*
193 * pfxlist_onlink_check -- プレフィックス・リストのオンリンク状態をチェックする。
194 *
195 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
196 * ロックしてから呼び出すこと。
197 */
198
199static void
200pfxlist_onlink_check (void)
201{
202 T_IFNET *ifp = IF_GET_IFNET();
203 T_ND6_PREFIX *pr = NULL;
204 T_IN6_IFADDR *ia;
205 ER error;
206 int_t ix;
207
208 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
209 pr = &nd6_prefix[ix];
210 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) != 0 &&
211 find_pfxlist_reachable_router(pr))
212 break;
213 }
214
215 if (ix >= 0) {
216 /*
217 * オンリンク状態のプレフィックスが最低一つ存在するときの処理。
218 * 各プレフィックスのオンリンク状態を、それらを通知してきたルータの
219 * 状態に従って設定する。
220 */
221
222
223 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
224 pr = &nd6_prefix[ix];
225
226 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) == 0)
227 continue;
228
229 if ((pr->flags & ND6_PREFIX_STATE_DETACHED) == 0 &&
230 find_pfxlist_reachable_router(pr) == NULL)
231 pr->flags |= ND6_PREFIX_STATE_DETACHED;
232
233 if ((pr->flags & ND6_PREFIX_STATE_DETACHED) != 0 &&
234 find_pfxlist_reachable_router(pr) != NULL)
235 pr->flags &= ~ND6_PREFIX_STATE_DETACHED;
236 }
237 }
238 else {
239 /*
240 * どのプレフィックスもオンリンクではなく、
241 * ディフォルトルータも存在しないときの処理。
242 * すべてのプレフィックスを使用可能状態に設定する。
243 */
244
245
246 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
247 pr = &nd6_prefix[ix];
248
249 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) == 0)
250 continue;
251
252 if ((pr->flags & ND6_PREFIX_STATE_DETACHED) != 0)
253 pr->flags &= ~ND6_PREFIX_STATE_DETACHED;
254 }
255 }
256
257 /*
258 * 各プレフィックス毎に、通知してきたルータの状態と
259 * オンリンクの状態が一致しなければ、オンリンク状態を更新する。
260 */
261 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
262 pr = &nd6_prefix[ix];
263
264 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) == 0)
265 continue;
266
267 if ((pr->flags & ND6_PREFIX_STATE_DETACHED) != 0 &&
268 (pr->flags & ND6_PREFIX_STATE_ONLINK ) != 0) {
269 if ((error = nd6_prefix_offlink(pr)) != E_OK)
270 syslog(LOG_ERROR, "[ND6 RTR] prefix offlink failed: %s", itron_strerror(error));
271 }
272
273 if ((pr->flags & ND6_PREFIX_STATE_DETACHED) == 0 &&
274 (pr->flags & ND6_PREFIX_STATE_ONLINK ) == 0 &&
275 (pr->flags & ND6_PREFIX_FLAG_ONLINK ) == 0) {
276 if ((error = nd6_prefix_onlink(pr)) != E_OK)
277 syslog(LOG_ERROR, "[ND6 RTR] prefix onlink failed: %s", itron_strerror(error));
278 }
279 }
280
281 /*
282 * リンク上にプレフィックスを通知しているルータが
283 * 少なくとも 1 台存在するか確認する。
284 */
285 for (ix = NUM_IN6_IFADDR_ENTRY; ix -- > 0; ) {
286 ia = &ifp->in_ifaddrs[ix];
287 if ((ia->flags & (IN6_IFF_DEFINED | IN6_IFF_AUTOCONF)) != 0 &&
288 ia->prefix_index != ND6_PREFIX_IX_INVALID) {
289 pr = &nd6_prefix[ia->prefix_index];
290 if (find_pfxlist_reachable_router(pr) != NULL)
291 break;
292 }
293 }
294
295 if (ix >= 0) {
296 /*
297 * リンク上にプレフィックスを通知しているルータが
298 * 少なくとも 1 台存在する時の処理。
299 */
300 for (ix = NUM_IN6_IFADDR_ENTRY; ix -- > 0; ) {
301 ia = &ifp->in_ifaddrs[ix];
302 if ((ia->flags & (IN6_IFF_DEFINED | IN6_IFF_AUTOCONF)) != 0 &&
303 ia->prefix_index != ND6_PREFIX_IX_INVALID) {
304 pr = &nd6_prefix[ia->prefix_index];
305 if (find_pfxlist_reachable_router(pr) != NULL)
306 ia->flags &= ~IN6_IFF_DETACHED;
307 else
308 ia->flags |= IN6_IFF_DETACHED;
309 }
310 }
311 }
312 else {
313 /*
314 * リンク上にプレフィックスを通知しているルータが
315 * 1 台存在しない時は全てのアドレスを利用できるようにする。
316 */
317 for (ix = NUM_IN6_IFADDR_ENTRY; ix -- > 0; ) {
318 ia = &ifp->in_ifaddrs[ix];
319 if ((ia->flags & (IN6_IFF_DEFINED | IN6_IFF_AUTOCONF)) != 0)
320 ia->flags &= ~IN6_IFF_DETACHED;
321 }
322 }
323 }
324
325/*
326 * pfxrtr_add -- プレフィックスエントリとディフォルトルータ・エントリをリンクする。
327 *
328 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
329 * ロックしてから呼び出すこと。
330 */
331
332static void
333pfxrtr_add (int_t prefix_index, int_t rtr_index)
334{
335 /* プレフィックスエントリとディフォルトルータ・エントリをリンクする。*/
336 nd6_prefix[prefix_index].routermap |= make_mask(rtr_index);
337 nd6_def_router[rtr_index].plistmap |= make_mask(prefix_index);
338
339 pfxlist_onlink_check();
340 }
341
342/*
343 * nd6_pfxrtr_lookup -- プレフィックスエントリからルータを探索する。
344 */
345
346static uint_t
347pfxrtr_lookup (const T_ND6_PREFIX *pr, int_t rtr_index)
348{
349 return (pr->routermap & make_mask(rtr_index)) == 0 ? IN6_RTR_IX_UNREACH : rtr_index;
350 }
351
352/*
353 * defrouter_select -- 優先ディフォルト・ルータを選択しなおす。
354 *
355 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
356 * ロックしてから呼び出すこと。
357 */
358
359static void
360defrouter_select (void)
361{
362 T_DEF_ROUTER *dr = NULL, router;
363 T_LLINFO_ND6 *ln;
364 int_t ix, tix;
365
366 for (ix = 0; ix < def_router_count; ix ++) {
367 dr = &nd6_def_router[ix];
368 if ((ln = nd6_lookup(&dr->addr, false)) != NULL && ND6_IS_LLINFO_PROBREACH(ln)) {
369
370 /* 選択したルータを先頭に移す。*/
371 router = *dr;
372 for (tix = ix; tix > 0; tix --)
373 nd6_def_router[tix] = nd6_def_router[tix - 1];
374 nd6_def_router[0] = router;
375 break;
376 }
377 }
378 }
379
380/*
381 * defrtrlist_update -- ディフォルトルータ・リストを更新する。
382 *
383 * 戻り値は、ルータのインデックス。
384 * ただし、値が -1 なら、プレフィックス・リストは更新しない。
385 */
386
387static int_t
388defrtrlist_update (T_IN6_ADDR *src, uint32_t lifetime, uint8_t flags)
389{
390 T_DEF_ROUTER *dr, *fdr = NULL;
391 SYSTIM now;
392 int_t ix;
393
394 syscall(get_tim(&now));
395 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
396
397 /* 登録済か調べる。*/
398 if ((fdr = nd6_defrtrlist_lookup(src)) != NULL) {
399 /* 登録済みの場合の処理 */
400 if (lifetime == 0) {
401 nd6_defrtrlist_del(fdr);
402 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
403 return -1;
404 }
405 else {
406 fdr->lifetime = lifetime * SYSTIM_HZ; /* lifetime の単位は秒 */
407 fdr->flags = flags;
408 fdr->expire = now + fdr->lifetime;
409 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
410 return fdr - nd6_def_router;
411 }
412 }
413 else if (lifetime == 0) {
414 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
415 return -1;
416 }
417
418 if (fdr == NULL && def_router_count < NUM_ND6_DEF_RTR_ENTRY) {
419 /*
420 * def_router_count < NUM_ND6_DEF_RTR_ENTRY であれば、
421 * nd6_def_router[def_router_count]; が空きエントリ
422 */
423 fdr = &nd6_def_router[def_router_count];
424 }
425
426 /* 空きエントリがなければ、有効時間が短いエントリを削除する。*/
427 if (fdr == NULL) {
428 T_DEF_ROUTER *sdr = NULL;
429 int32_t diff, sdiff = 0xffffffff;
430
431 for (ix = def_router_count; ix -- > 0; ) {
432 dr = &nd6_def_router[ix];
433 diff = (int32_t)(dr->expire - now);
434 if (diff <= 0) { /* dr->expire <= now */
435 /* 既に、有効時間が過ぎている。*/
436 sdr = dr;
437 break;
438 }
439 else if (diff < sdiff)
440 sdr = dr;
441 }
442 if (sdr != NULL) {
443 fdr = sdr;
444 nd6_defrtrlist_del(fdr);
445 }
446 }
447
448 /* 各メンバに値を設定する。*/
449 fdr->plistmap = 0;
450 fdr->addr = *src;
451 fdr->lifetime = lifetime * SYSTIM_HZ; /* lifetime の単位は秒 */
452 fdr->flags = flags;
453 fdr->expire = now + fdr->lifetime;
454 fdr->state = ND6_DEF_RTR_BUSY;
455 def_router_count ++;
456
457 /*
458 * ディフォルトルータとして登録するが、
459 * 既にディフォルトルータがあれば選択しなおさない。
460 */
461 if (fdr - nd6_def_router != 0)
462 defrouter_select();
463
464 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
465 return fdr - nd6_def_router;
466 }
467
468/*
469 * in6_ifadd -- インタフェースにアドレスを追加する。
470 */
471
472static ER
473in6_ifadd (T_ND6_PREFIX *pr, T_IN6_IFADDR *ia, int_t router_index)
474{
475 T_IFNET *ifp = IF_GET_IFNET();
476 T_IN6_ADDR mask, addr;
477 T_IN6_IFADDR *lla;
478 int_t ix;
479
480 lla = &ifp->in_ifaddrs[IPV6_IFADDR_IX_LINKLOCAL];
481
482 /*
483 * リンクローカルアドレスが未登録であれば何もしない。
484 */
485 if ((lla->flags & IN6_IFF_DEFINED) == 0)
486 return E_OBJ;
487
488 /*
489 * ルータから通知されたプレフィックス長が、
490 * リンクローカルアドレスのプレフィックス長と
491 * 異なっていればエラー
492 */
493 if (lla->prefix_len != pr->prefix_len)
494 return E_PAR;
495
496 /* プレフィックスマスクを生成する。*/
497 in6_plen2pmask(&mask, pr->prefix_len);
498
499 /* アドレスを生成する。*/
500 for (ix = 0; ix < 4; ix ++)
501 addr.s6_addr32[ix] = (pr->prefix.s6_addr32[ix] & mask.s6_addr32[ix])
502 | ( lla->addr.s6_addr32[ix] & ~mask.s6_addr32[ix]);
503
504 /* フラグを初期化する。*/
505 ia->flags = 0;
506
507 return in6_update_ifa(ifp, ia, &addr,
508 pr->prefix_len, pr->vltime, pr->pltime,
509 router_index, pr - nd6_prefix, IN6_IFF_AUTOCONF);
510 }
511
512/*
513 * nd6_prefix_lookup -- プレフィックスを探索する。
514 */
515
516static T_ND6_PREFIX *
517nd6_prefix_lookup (const T_IN6_ADDR *prefix, uint_t plen)
518{
519 T_ND6_PREFIX *pr;
520 int_t ix;
521
522 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
523 pr = &nd6_prefix[ix];
524 if ((pr->flags & ND6_PREFIX_STATE_BUSY) &&
525 pr->prefix_len == plen && IN6_ARE_ADDR_EQUAL(&pr->prefix, prefix))
526 return pr;
527 }
528
529 return NULL;
530 }
531
532/*
533 * prelist_remove -- プレフィックスリストからプレフィックスを削除する。
534 *
535 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
536 * ロックしてから呼び出すこと。
537 */
538
539static void
540prelist_remove (T_ND6_PREFIX *pr)
541{
542 ER error = E_OK;
543 uint_t mask;
544 int_t rix;
545
546 /* 有効時間切れにする。*/
547 pr->vltime = 0;
548 pr->pltime = 0;
549
550 if ((pr->flags & ND6_PREFIX_STATE_ONLINK) != 0 &&
551 (error = nd6_prefix_offlink(pr)) != E_OK) {
552 syslog(LOG_ERROR, "[ND6 RTR] prefix remove failed: %s", itron_strerror(error));
553 return;
554 }
555
556 /* プレフィックスエントリとディフォルトルータ・エントリのリンクを解除する。*/
557 pr->routermap = 0;
558 mask = make_mask(pr - nd6_prefix);
559 for (rix = def_router_count; rix --; )
560 nd6_def_router[rix].plistmap &= ~mask;
561
562 /* プレフィックスを無効にする。*/
563 pr->flags &= ~ND6_PREFIX_STATE_BUSY;
564
565 pfxlist_onlink_check();
566 }
567
568/*
569 * nd6_prefix_onlink -- プレフィックスをオンリンクに設定し、アドレスを使用可能にする。
570 *
571 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
572 * ロックしてから呼び出すこと。
573 */
574
575ER
576nd6_prefix_onlink (T_ND6_PREFIX *pr)
577{
578 T_IFNET *ifp = IF_GET_IFNET();
579 T_IN6_IFADDR *lla, *ia = NULL;
580 int_t ix;
581
582 /* 既にオンリンク状態になっている場合はエラー。*/
583 if ((pr->flags & ND6_PREFIX_STATE_ONLINK) != 0)
584 return E_OBJ;
585
586 /* リンクローカルアドレスが未登録であれば何もしない。*/
587 lla = &ifp->in_ifaddrs[IPV6_IFADDR_IX_LINKLOCAL];
588 if ((lla->flags & IN6_IFF_DEFINED) == 0)
589 return E_OK;
590
591 /*
592 * 指定されたプレフィックスが割り当てられているインタフェースの
593 * アドレス情報を探す。
594 */
595 for (ix = NUM_IN6_IFADDR_ENTRY; ix --; ) {
596 ia = &ifp->in_ifaddrs[ix];
597 if (ia->prefix_index == (pr - nd6_prefix))
598 break;
599 }
600
601 if (ix >= 0) {
602
603 /* アドレス情報を使用可能にする。*/
604 ia->flags &= ~IN6_IFF_DETACHED;
605
606 /* プレフィックスをオンリンクに設定する。*/
607 pr->flags |= ND6_PREFIX_STATE_ONLINK;
608 }
609
610 return E_OK;
611 }
612
613/*
614 * nd6_prefix_offlink -- プレフィックスをオフリンクに設定し、アドレスを使用不可にする。
615 *
616 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
617 * ロックしてから呼び出すこと。
618 */
619
620ER
621nd6_prefix_offlink (T_ND6_PREFIX *pr)
622{
623 T_IFNET *ifp = IF_GET_IFNET();
624 T_IN6_IFADDR *ia = NULL;
625 int_t ix;
626
627 /* 既にオフリンク状態になっている場合はエラー。*/
628 if ((pr->flags & ND6_PREFIX_STATE_ONLINK) == 0)
629 return E_OBJ;
630
631 /*
632 * 指定されたプレフィックスが割り当てられているインタフェースの
633 * アドレス情報を探す。
634 */
635 for (ix = NUM_IN6_IFADDR_ENTRY; ix --; ) {
636 ia = &ifp->in_ifaddrs[ix];
637 if (ia->prefix_index == (pr - nd6_prefix))
638 break;
639 }
640
641 if (ix >= 0) {
642
643 /* アドレス情報を使用不可にする。*/
644 ia->flags |= IN6_IFF_DETACHED;
645
646 /* プレフィックスをオフリンクに設定する。*/
647 pr->flags &= ~ND6_PREFIX_STATE_ONLINK;
648 }
649
650 return E_OK;
651 }
652
653/*
654 * in6_init_prefix_ltimes -- プレフィックスの有効時間を設定する。
655 */
656
657static ER
658in6_init_prefix_ltimes (T_ND6_PREFIX *pr)
659{
660 SYSTIM now;
661
662 /* 推奨有効時間が有効時間より長いときはエラー */
663 if (pr->pltime > pr->vltime)
664 return E_PAR;
665
666 syscall(get_tim(&now));
667 now /= SYSTIM_HZ;
668
669 if (pr->pltime == ND6_INFINITE_LIFETIME)
670 pr->preferred = 0;
671 else
672 pr->preferred = pr->pltime + now;
673
674 if (pr->vltime == ND6_INFINITE_LIFETIME)
675 pr->expire = 0;
676 else
677 pr->expire = pr->vltime + now;
678
679 return E_OK;
680 }
681
682/*
683 * nd6_prelist_add -- プレフィックスリストにプレフィックスを追加する。
684 *
685 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
686 * ロックしてから呼び出すこと。
687 */
688
689static T_ND6_PREFIX *
690nd6_prelist_add (T_ND_OPT_PREFIX_INFO *pi, int_t rtr_index)
691{
692 T_ND6_PREFIX *pr = NULL;
693 int_t ix;
694 ER error;
695
696 /* プレフィックスリストから空きのプレフィックスエントリを探索する。*/
697 for (ix = NUM_ND6_PREFIX_ENTRY; ix --; ) {
698 pr = &nd6_prefix[ix];
699 if ((pr->flags & ND6_PREFIX_STATE_BUSY) == 0)
700 break;
701 }
702
703 /* プレフィックスリストに空きがなければエラー */
704 if (ix < 0)
705 return NULL;
706
707 pr->flags |= ND6_PREFIX_STATE_BUSY;
708
709 /* プレフィックスを追加する。*/
710 pr->prefix = pi->prefix;
711 pr->prefix_len = pi->prefix_len;
712
713 /* フラグを設定する。*/
714 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK) != 0)
715 pr->flags |= ND6_PREFIX_FLAG_ONLINK;
716 if ((pi->flags & ND_OPT_PI_FLAG_AUTO) != 0)
717 pr->flags |= ND6_PREFIX_FLAG_AUTO;
718
719 /* プレフィックスの有効時間を設定する。*/
720 pr->vltime = ntohl(pi->valid);
721 pr->pltime = ntohl(pi->preferred);
722 in6_init_prefix_ltimes(pr);
723
724 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) != 0) {
725 if ((error = nd6_prefix_onlink(pr)) != E_OK)
726 return NULL;
727 }
728
729 /* ルータマップを初期化する。*/
730 pr->routermap = 0;
731
732 /* ルータを追加する。*/
733 pfxrtr_add(pr - nd6_prefix, rtr_index);
734
735 return pr;
736 }
737
738/*
739 * prelist_update -- プレフィックス・リストを更新する。
740 */
741
742static void
743prelist_update (T_ND_OPT_PREFIX_INFO *pi, uint_t router_index)
744{
745 T_IFNET *ifp = IF_GET_IFNET();
746 T_ND6_PREFIX *pr;
747 T_IN6_IFADDR *ia = NULL;
748 int_t ix, ifidlen;
749
750 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
751 if ((pr = nd6_prefix_lookup(&pi->prefix, pi->prefix_len)) != NULL) {
752 /*
753 * 登録済みの場合は、プレフィックスリストを更新する。
754 */
755
756 /*
757 * フラグの更新の注意:
758 * on-link ビットと autonomous ビットは
759 * 1 から 0 に変更してはならない。
760 */
761
762 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK) != 0)
763 pr->flags |= ND6_PREFIX_FLAG_ONLINK;
764 if ((pi->flags & ND_OPT_PI_FLAG_AUTO) != 0)
765 pr->flags |= ND6_PREFIX_FLAG_AUTO;
766
767 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK) != 0) {
768 /*
769 * 通知されたプレフィックスがオンリンクの時は、
770 * 有効時間を更新する。
771 */
772 pr->vltime = ntohl(pi->valid);
773 pr->pltime = ntohl(pi->preferred);
774 in6_init_prefix_ltimes(pr);
775 }
776
777 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK ) != 0 &&
778 (pr->flags & ND6_PREFIX_STATE_ONLINK) == 0) {
779 /*
780 * オフリンクのプレフィックスがオンリンクになった時の処理を実行する。
781 */
782 if (nd6_prefix_onlink(pr) != E_OK) {
783 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
784 syslog(LOG_ERROR, "[ND6 RTR] prefix update failed.");
785 return;
786 }
787 }
788
789 if (router_index != IN6_RTR_IX_UNREACH && pfxrtr_lookup(pr, router_index) == IN6_RTR_IX_UNREACH)
790 pfxrtr_add(pr - nd6_prefix, router_index);
791 }
792 else { /* 未登録の場合 */
793
794 /* 有効時間 0 のプレフィックスは追加しない。*/
795 if (pi->valid == 0) {
796 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
797 return;
798 }
799
800 /* オフリンクでアドレス自動設定に使用しなければ追加しない。*/
801 if ((pi->flags & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO)) !=
802 (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO)) {
803 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
804 return;
805 }
806
807 /* プレフィックスを追加する。*/
808 if ((pr = nd6_prelist_add(pi, router_index)) == NULL) {
809 syslog(LOG_ERROR, "[ND6 RTR] prefix add failed.");
810 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
811 return;
812 }
813
814 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) == 0) {
815 /*
816 * オフリンク・プレフィックスの場合は、有効時間を 0 に設定する。
817 * あとで有効期限切れとなり、リストから削除される。
818 */
819 pr->vltime = 0;
820 pr->pltime = 0;
821 in6_init_prefix_ltimes(pr);
822 }
823 }
824
825 /*
826 * ステートレス・アドレス自動設定を行う。
827 */
828 if ((pr->flags & ND6_PREFIX_FLAG_AUTO) == 0) {
829 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
830 return;
831 }
832
833 /*
834 * 通知されたプレフィックスが割り当てられているインタフェースの
835 * アドレス情報を探す。
836 */
837 for (ix = NUM_IN6_IFADDR_ENTRY; ix --; ) {
838 ia = &ifp->in_ifaddrs[ix];
839 if ((ia->flags & IN6_IFF_DEFINED) != 0 &&
840 ia->prefix_len == pr->prefix_len &&
841 in6_are_prefix_equal(&ia->addr, &pr->prefix, pr->prefix_len))
842 break;
843 }
844
845 if (ix >= 0) { /* 登録済みのとき */
846 if ((ia->flags & IN6_IFF_AUTOCONF) == 0) {
847 /*
848 * ステートレス・アドレス自動設定により
849 * 設定されていなければ更新しない。
850 */
851 ;
852 }
853 else if (ia->flags & IN6_IFF_TENTATIVE) {
854 /*
855 * 重複検出中なら更新しない。
856 */
857 ;
858 }
859 else {
860 T_IN6_ADDR mask, addr;
861 T_IN6_IFADDR *lla;
862 uint32_t vltime;
863 SYSTIM now;
864 int_t ix;
865
866 /* 有効時間を設定する。*/
867 syscall(get_tim(&now));
868
869 if (ia->lifetime.vltime == ND6_INFINITE_LIFETIME)
870 vltime = ND6_INFINITE_LIFETIME;
871 else if (IFA6_IS_INVALID(ia, now))
872 vltime = 0;
873 else
874 vltime = ia->lifetime.expire - now / SYSTIM_HZ;
875
876 if (pr->vltime > (2 * 60 * 60) || pr->vltime > vltime) {
877 /*
878 * lifetime.expire、pi->valid (有効時間) と
879 * pi->preferred (推奨有効時間) の単位は [s]。
880 * 通知された有効時間が 2 時間以上か、現在の残り時間より
881 * 長ければ、新しい有効時間には、通知された有効時間を設定する。
882 */
883 vltime = pr->vltime;
884 }
885 else if (vltime <= (2 * 60 * 60))
886 ;
887 else {
888 /*
889 * IPsec は未実装のため、2 時間を設定する。
890 */
891 vltime = 2 * 60 * 60;
892 }
893
894 lla = &ifp->in_ifaddrs[IPV6_IFADDR_IX_LINKLOCAL];
895
896 /* プレフィックスマスクを生成する。*/
897 in6_plen2pmask(&mask, pr->prefix_len);
898
899 /* アドレスを生成する。*/
900 for (ix = 0; ix < 4; ix ++)
901 addr.s6_addr32[ix] = (pr->prefix.s6_addr32[ix] & mask.s6_addr32[ix])
902 | ( lla->addr.s6_addr32[ix] & ~mask.s6_addr32[ix]);
903
904 in6_update_ifa(ifp, ia, &addr, pr->prefix_len, vltime,
905 pr->pltime, router_index, pr - nd6_prefix,
906 IN6_IFF_AUTOCONF | IN6_IFF_NODAD);
907 }
908 }
909
910 else { /* 未登録のとき */
911
912 /*
913 * プレフィックス長をチェックする。
914 * もし、プレフィックス長とインタフェース ID の合計が
915 * 128 ビットに一致しない時は、プレフィックス情報を無視する。
916 */
917 if ((ifidlen = in6_if2idlen(ifp)) < 0)
918 syslog(LOG_ERROR, "[ND6 RTR] IFID undefined.");
919 else if (ifidlen + pr->prefix_len != 128)
920 syslog(LOG_NOTICE, "[ND6 RTR] invalid prefix len: %d.", pr->prefix_len);
921 else {
922
923 for (ix = NUM_IN6_IFADDR_ENTRY; ix --; ) {
924 ia = &ifp->in_ifaddrs[ix];
925 if ((ia->flags & IN6_IFF_DEFINED) == 0) {
926 in6_ifadd(pr, ia, router_index);
927 pfxlist_onlink_check();
928 break;
929 }
930 }
931
932 if (ix < 0)
933 syslog(LOG_ERROR, "[ND6 RTR] prefix update failed.");
934 }
935 }
936 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
937 }
938
939/*
940 * nd6_prelist_timer -- プレフィックス・リストの管理タイマー
941 */
942
943void
944nd6_prelist_timer (void)
945{
946 T_ND6_PREFIX *pr;
947 SYSTIM now;
948 int_t ix;
949
950 syscall(get_tim(&now));
951 now /= SYSTIM_HZ; /* 有効時間の単位は [s] */
952
953 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
954 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
955 pr = &nd6_prefix[ix];
956 if ((pr->flags & ND6_PREFIX_STATE_BUSY) != 0 && (int32_t)(pr->expire - now) <= 0)
957 /* pr->expire <= now */
958 prelist_remove(pr);
959 }
960 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
961 }
962
963/*
964 * nd6_rs_output -- ルータ要請を出力する。
965 */
966
967static void
968nd6_rs_output (void)
969{
970 T_ROUTER_SOLICIT_HDR *rsh;
971 T_NET_BUF *output;
972 T_IN6_IFADDR *ifa;
973 T_IN6_ADDR *saddr;
974 uint16_t len;
975
976 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_RS_OUT_PACKETS], 1);
977
978 /*
979 * 送信元アドレスには、リンクローカルアドレスを設定するが、
980 * まだ設定されいなければ、無指定を設定する。
981 */
982 if ((ifa = in6ifa_ifpwithix(IF_GET_IFNET(), IPV6_IFADDR_IX_LINKLOCAL)) != NULL && !IFA6_IS_NOTREADY(ifa))
983 saddr = &ifa->addr;
984 else
985 saddr = &in6_addr_unspecified;
986
987 len = (ROUTER_SOLICIT_HDR_SIZE + 7) >> 3 << 3;
988
989 /* ネットワークバッファを獲得し、IPv6 ヘッダを設定する。*/
990 if (in6_get_datagram(&output, len, 0, &in6_addr_linklocal_allrouters,
991 saddr, IPPROTO_ICMPV6,
992 IPV6_MAXHLIM, NBA_SEARCH_ASCENT, TMO_ND6_RS_OUTPUT) != E_OK)
993 return;
994
995 /* ルータ要請ヘッダを設定する。*/
996 rsh = GET_ROUTER_SOLICIT_HDR(output, IF_IP6_ROUTER_SOLICIT_HDR_OFFSET);
997 rsh->hdr.type = ND_ROUTER_SOLICIT;
998 rsh->hdr.code = 0;
999 rsh->nd_rs_reserved = 0;
1000
1001 /* チェックサムを計算する。*/
1002 rsh->hdr.sum = 0;
1003 rsh->hdr.sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)rsh - output->buf, len);
1004
1005 /* 送信する。*/
1006 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_OCTETS],
1007 output->len - GET_IF_IP6_HDR_SIZE(output));
1008 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_PACKETS], 1);
1009 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
1010 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutRouterSolicits, 1);
1011 ip6_output(output, IPV6_OUT_SET_HOP_LIMIT(IPV6_OUT_FLG_HOP_LIMIT, IPV6_MAXHLIM), TMO_ND6_RS_OUTPUT);
1012 }
1013
1014/*
1015 * nd6_defrtrlist_lookup -- ディフォルトルータ・リストを探索する。
1016 */
1017
1018T_DEF_ROUTER *
1019nd6_defrtrlist_lookup (T_IN6_ADDR *src)
1020{
1021 T_DEF_ROUTER *dr = NULL;
1022 int_t ix;
1023
1024 for (ix = def_router_count; ix -- > 0; ) {
1025 dr = &nd6_def_router[ix];
1026 if (IN6_ARE_ADDR_EQUAL(&dr->addr, src)) {
1027 return dr;
1028 }
1029 }
1030 return NULL;
1031 }
1032
1033/*
1034 * nd6_router_lookup -- ルータのアドレスを返す。
1035 *
1036 */
1037
1038T_IN6_ADDR *
1039nd6_router_lookup (void)
1040{
1041 if (def_router_count > 0)
1042 return &nd6_def_router[0].addr;
1043 else
1044 return NULL;
1045 }
1046
1047/*
1048 * nd6_defrtrlist_del -- ディフォルトルータ・リストからルータを削除する。
1049 *
1050 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
1051 * ロックしてから呼び出すこと。
1052 */
1053
1054void
1055nd6_defrtrlist_del (T_DEF_ROUTER *dr)
1056{
1057 T_IFNET *ifp = IF_GET_IFNET();
1058 T_IN6_IFADDR *ia;
1059 T_ND6_PREFIX *pr;
1060 uint_t mask;
1061 int_t ix, rix, pix, rtrix = dr - nd6_def_router;
1062
1063 if ((ia = in6ifa_ifpwithrtrix(ifp, rtrix)) != NULL) {
1064 /*
1065 * ネットワークインタフェースのプレフィックスを通知した
1066 * ルータを到達不能にする。
1067 */
1068 ia->router_index = IN6_RTR_IX_UNREACH;
1069 }
1070
1071 /* プレフィックスリストからルータを削除する。*/
1072 mask = make_mask(rtrix);
1073 for (pix = NUM_ND6_PREFIX_ENTRY; pix --; )
1074 nd6_prefix[pix].routermap &= ~mask;
1075
1076 /* 削除したルータ以降を前に詰める。*/
1077 for (rix = rtrix + 1; rix < def_router_count; rix ++)
1078 nd6_def_router[rix - 1] = nd6_def_router[rix];
1079
1080 /* プレフィックスリストのルータも更新する。*/
1081 if (dr != nd6_def_router) {
1082
1083 /* マスクを生成する。*/
1084 mask = 1;
1085 for (ix = rtrix - 1; ix -- > 0; )
1086 mask = (mask << 1) | 1;
1087
1088 for (pix = NUM_ND6_PREFIX_ENTRY; pix --; ) {
1089 pr = &nd6_prefix[pix];
1090 pr->routermap = (pr->routermap & mask) | (((pr->routermap & ~mask) >> 1) & ~mask);
1091 }
1092 }
1093 def_router_count --;
1094
1095 /* プレフィックスのオンリンク状態を確認する。*/
1096 pfxlist_onlink_check();
1097
1098 /*
1099 * 削除するルータが優先ディフォルトルータの場合は、
1100 * 優先ディフォルトルータを選択しなおす。
1101 */
1102 if (rtrix == 0)
1103 defrouter_select();
1104 }
1105
1106/*
1107 * nd6_defrtrlist_timer -- ディフォルトルータ・リストの管理タイマー
1108 */
1109
1110void
1111nd6_defrtrlist_timer (void)
1112{
1113 T_DEF_ROUTER *dr;
1114 SYSTIM now;
1115 int_t ix;
1116
1117 syscall(get_tim(&now));
1118
1119 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
1120 for (ix = def_router_count; ix -- > 0; ) {
1121 dr = &nd6_def_router[ix];
1122 if ((int32_t)(dr->expire - now) <= 0) {
1123 /* dr->expire <= now */
1124 nd6_defrtrlist_del(dr);
1125 }
1126 }
1127 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
1128 }
1129
1130/*
1131 * nd6_get_drl -- ディフォルトルータ・リストを獲得する。
1132 */
1133
1134const T_DEF_ROUTER *
1135nd6_get_drl (uint_t *count)
1136{
1137 *count = def_router_count;
1138 return nd6_def_router;
1139 }
1140
1141/*
1142 * nd6_get_prl -- プレフィックス・リストを獲得する。
1143 */
1144
1145const T_ND6_PREFIX *
1146nd6_get_prl (void)
1147{
1148 return nd6_prefix;
1149 }
1150
1151#endif /* of #if NUM_ND6_DEF_RTR_ENTRY > 0 */
1152
1153/*
1154 * nd6_ra_input -- ルータ通知の入力処理。
1155 */
1156
1157void
1158nd6_ra_input (T_NET_BUF *input, uint_t off)
1159{
1160#if NUM_ND6_DEF_RTR_ENTRY > 0
1161
1162 T_IFNET *ifp = IF_GET_IFNET();
1163 T_IP6_HDR *ip6h;
1164 T_ROUTER_ADVERT_HDR *rah;
1165 T_ND_OPT_HDR *opth;
1166 SYSTIM now;
1167 int_t rix;
1168 uint_t lladdr_len = 0;
1169 uint32_t advrea;
1170 uint8_t *lladdr = NULL;
1171 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
1172
1173 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_RA_IN_PACKETS], 1);
1174
1175 ip6h = GET_IP6_HDR(input);
1176
1177 /*
1178 * ヘッダのチェック、以下の場合は破棄する。
1179 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
1180 * ・ヘッダ長が短い
1181 * ・始点アドレスが、リンクローカルではない (RFC2461)
1182 */
1183 if (ip6h->hlim != IPV6_MAXHLIM ||
1184 input->len - off < ROUTER_ADVERT_HDR_SIZE ||
1185 !IN6_IS_ADDR_LINKLOCAL(&ip6h->src))
1186 goto err_ret;
1187
1188 rah = GET_ROUTER_ADVERT_HDR(input, off);
1189
1190 /* 近隣探索オプションのオフセットを記録する。*/
1191 if (nd6_options(nd_opt_off, input->buf + (off + ROUTER_ADVERT_HDR_SIZE),
1192 input->len - (off + ROUTER_ADVERT_HDR_SIZE)) != E_OK)
1193 goto err_ret;
1194 /*
1195 * 到達可能状態の有効時間の更新
1196
1197 */
1198 if (rah->reachable) {
1199 advrea = ntohl(rah->reachable) * SYSTIM_HZ / 1000; /* rah->reachable の単位は ms */
1200 if (advrea <= ND6_MAX_REACHABLE_TIME &&
1201 advrea != nd6_base_reachable_time) {
1202 syscall(get_tim(&now));
1203 nd6_recalc_reachtm_interval
1204 = now + ND6_RECALC_REACHTM_INTERVAL;
1205 nd6_base_reachable_time = advrea;
1206 nd6_reachable_time
1207 = ND6_CALC_REACH_TIME(nd6_base_reachable_time);
1208 }
1209 }
1210
1211 /* 近隣探索の送信間隔の更新 */
1212 if (rah->retransmit) {
1213 nd6_retrans_time = ntohl(rah->retransmit) * SYSTIM_HZ / 1000;
1214 /* rah->retransmit の単位は ms */
1215 }
1216
1217 /* ホップリミットの規定値の更新 */
1218 if (rah->nd_ra_current_hoplimit) {
1219 ip6_defhlim = rah->nd_ra_current_hoplimit;
1220 }
1221
1222 /* ディフォルトルータリストの更新 */
1223 rix = defrtrlist_update(&ip6h->src,
1224 ntohs(rah->nd_ra_router_lifetime),
1225 rah->nd_ra_flags); /* rah->nd_ra_router_lifetime の単位は秒 */
1226
1227 /* プレフィックスリストの更新 */
1228 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_PREFIX_INFO_COUNT)]) {
1229 T_ND_OPT_PREFIX_INFO *pi;
1230 uint_t pi_off, pi_count;
1231
1232 pi_count = nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_PREFIX_INFO_COUNT)];
1233 pi_off = off + ROUTER_ADVERT_HDR_SIZE
1234 + nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_PREFIX_INFORMATION)] - 8;
1235 /* 注意: オプションオフセット配列には、オフセット + 8 が設定されている。*/
1236 while (pi_count -- > 0) {
1237 pi = (T_ND_OPT_PREFIX_INFO*)(input->buf + pi_off);
1238 if (pi->type != ND_OPT_PREFIX_INFORMATION)
1239 /* オプションタイプがプレフィックス情報でなければ何もしない。*/
1240 ;
1241 else if (pi->len != 4)
1242 /* プレフィックス情報の長さが 32 (8×4) でなければ不正 */
1243 syslog(LOG_NOTICE, "[ND6 RTR] prefix opt len: %d.", pi->len);
1244 else if (pi->prefix_len > 128)
1245 /* プレフィックス長は 128 ビット以下 */
1246 syslog(LOG_NOTICE, "[ND6 RTR] prefix len: %d.", pi->prefix_len);
1247 else if (IN6_IS_ADDR_MULTICAST(&pi->prefix) ||
1248 IN6_IS_ADDR_LINKLOCAL(&pi->prefix))
1249 /* マルチキャストとリンクローカルは不正 */
1250 syslog(LOG_NOTICE, "[ND6 RTR] invalid addr: %s from %s.",
1251 ipv62str(NULL, &pi->prefix), ipv62str(NULL, &ip6h->src));
1252#if 0 /* FreeBSD 6.3 で削除されている。*/
1253 else if (IN6_IS_ADDR_AGGREGATE_UNICAST(&pi->prefix) &&
1254 (pi->prefix_len != 64) )
1255 /* 集約可能ユニキャストで、プレフィックス長が 64 ビット以外は不正 */
1256 syslog(LOG_NOTICE, "[ND6 RTR] invalid prefix len for global: %d.", pi->prefix_len);
1257#endif
1258 else if (ntohl(pi->preferred) > ntohl(pi->valid))
1259 /* 推奨有効時間が有効時間より長ければ不正 */
1260 syslog(LOG_NOTICE, "[ND6 RTR] preferred(%d) > valid time(%d).", ntohl(pi->preferred), ntohl(pi->valid));
1261 else {
1262 syslog(LOG_NOTICE, "[ND6 RTR] update prefix: %s from %s.",
1263 ipv62str(NULL, &pi->prefix), ipv62str(NULL, &ip6h->src));
1264 if (rix >= 0) {
1265 /*
1266 * defrtrlist_update の戻り値は、ルータのインデックス。
1267 * ただし、値が -1 なら、プレフィックス・リストは更新しない。
1268 */
1269 prelist_update(pi, rix); /* プレフィックス・リストを更新する。*/
1270 }
1271 }
1272 pi_off += pi->len << 3; /* オプション長の単位は 8 バイト */
1273 }
1274 }
1275
1276 /* MTU の更新 */
1277 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_MTU)]) {
1278 T_ND_OPT_MTU_HDR *optmtuh;
1279 uint32_t mtu;
1280
1281 optmtuh = (T_ND_OPT_MTU_HDR *)((uint8_t *)(input->buf + off + ROUTER_ADVERT_HDR_SIZE) +
1282 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_MTU)] - 8);
1283
1284 /*
1285 * 値のチェック
1286 *
1287 * オプション長: 1
1288 * 予約: 0
1289 */
1290 if (optmtuh->len != 1 || optmtuh->reserved != 0)
1291 goto err_ret;
1292
1293 /* MTU が IPv6 MMTU(1280 オクテット)以下なら無視する。*/
1294 mtu = ntohl(optmtuh->mtu);
1295 if (mtu >= IPV6_MMTU) {
1296 if (mtu <= (linkmtu > IF_MTU ? linkmtu : IF_MTU))
1297 linkmtu = mtu;
1298 }
1299 }
1300
1301 /*
1302 * ルータの始点リンクアドレスを近隣キャッシュに登録する。
1303 */
1304 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)]) {
1305 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + ROUTER_ADVERT_HDR_SIZE) +
1306 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)] - 8);
1307 /* 注意: オプションオフセット配列には、オフセット + 8 が設定されている。*/
1308 lladdr = (uint8_t *)(opth + 1);
1309 lladdr_len = (opth->len << 3);
1310 }
1311
1312 /*
1313 * ネットワークインタフェースのアドレス長が一致しなければエラー
1314 */
1315 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
1316 goto err_ret;
1317
1318 /* 近隣キャッシュに登録する。*/
1319 nd6_cache_lladdr(ifp, &ip6h->src, (T_IF_ADDR *)lladdr, ND_ROUTER_ADVERT, 0);
1320
1321 /*
1322 * ルータの始点リンクアドレスを近隣キャッシュに登録したので、
1323 * オンリンク状態が変化する可能性があるため、それをチェックする。
1324 */
1325 pfxlist_onlink_check();
1326
1327 syscall(rel_net_buf(input));
1328 return;
1329
1330err_ret:
1331 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
1332 syscall(rel_net_buf(input));
1333
1334#else /* of #if NUM_ND6_DEF_RTR_ENTRY > 0 */
1335
1336 /*
1337 * ルータ通知を受信しない場合は、破棄して終了する。
1338 */
1339 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_RA_IN_PACKETS], 1);
1340 syscall(rel_net_buf(input));
1341
1342#endif /* of #if NUM_ND6_DEF_RTR_ENTRY > 0 */
1343 }
1344
1345#if NUM_ND6_RTR_SOL_RETRY > 0
1346
1347/*
1348 * nd6_rtrsol_ctl -- ルータ要請出力の制御
1349 */
1350
1351void
1352nd6_rtrsol_ctl (void)
1353{
1354 T_IN6_IFADDR *ifa;
1355 int_t try;
1356
1357 /* リンクローカルアドレスのアドレス情報を得る。*/
1358 if ((ifa = in6ifa_ifpwithix(IF_GET_IFNET(), IPV6_IFADDR_IX_LINKLOCAL)) == NULL)
1359 return;
1360
1361 /* リンクローカルアドレスの重複検出終了を待つ。*/
1362 do {
1363 /* リンクローカルアドレスの重複検出終了待ち時間を設定する。*/
1364 syscall(dly_tsk(net_rand() % TMO_ND6_RTR_SOL_DELAY));
1365
1366 /* 待っている間に重複が検出されたら終了する。*/
1367 if (ifa->flags & IN6_IFF_DUPLICATED)
1368 return;
1369
1370 } while (!((ifa->flags & IN6_IFF_DEFINED) && (ifa->flags & IN6_IFF_TENTATIVE) == 0));
1371
1372 for (try = 0; try < NUM_ND6_RTR_SOL_RETRY; try ++) {
1373
1374 /* ディフォルトルータ・リストにエントリがあれば終了 */
1375 if (def_router_count > 0)
1376 return;
1377
1378 /* ルータ要請を出力する。*/
1379 nd6_rs_output();
1380
1381 /* 出力の 2 回目以降の遅延時間を設定する。*/
1382 syscall(dly_tsk(TMO_ND6_RTR_SOL_INTERVAL));
1383 }
1384 }
1385
1386#endif /* of #if NUM_ND6_RTR_SOL_RETRY > 0 */
1387
1388/*
1389 * nd6_onlink_prefix_lookup -- プレフィックスを探索する。
1390 */
1391
1392T_ND6_PREFIX *
1393nd6_onlink_prefix_lookup (T_IN6_ADDR *dst)
1394{
1395 SYSTIM now;
1396 T_ND6_PREFIX *pr;
1397 int_t ix;
1398
1399 syscall(get_tim(&now));
1400 now /= SYSTIM_HZ;
1401
1402 /* 推奨有効時間内のプレフィックスを探索する。*/
1403 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
1404 pr = &nd6_prefix[ix];
1405 if ((pr->flags & ND6_PREFIX_STATE_BUSY) &&
1406 (pr->flags & ND6_PREFIX_FLAG_ONLINK) &&
1407 in6_are_prefix_equal(dst, &pr->prefix, pr->prefix_len) &&
1408 (int32_t)(pr->preferred - now) > 0) {
1409 /* pr->preferred > now */
1410 return pr;
1411 }
1412 }
1413
1414 /* 有効時間内のプレフィックスを探索する。*/
1415 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
1416 pr = &nd6_prefix[ix];
1417 if ((pr->flags & ND6_PREFIX_STATE_BUSY) &&
1418 (pr->flags & ND6_PREFIX_FLAG_ONLINK) &&
1419 in6_are_prefix_equal(dst, &pr->prefix, pr->prefix_len) &&
1420 (int32_t)(pr->expire - now) > 0) {
1421 /* pr->expire > now */
1422 return pr;
1423 }
1424 }
1425
1426 return NULL;
1427 }
1428
1429#endif /* of #ifdef SUPPORT_INET6 */
Note: See TracBrowser for help on using the repository browser.