source: asp3_tinet_ecnl_rx/trunk/asp3_dcre/tinet/netinet6/nd6_rtr.c@ 337

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

ASP3版ECNLを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 41.5 KB
Line 
1/*
2 * TINET (TCP/IP Protocol Stack)
3 *
4 * Copyright (C) 2001-2017 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_endian.h>
96#include <net/net_var.h>
97#include <net/net_buf.h>
98#include <net/net_timer.h>
99#include <net/net_count.h>
100
101#include <netinet/in.h>
102#include <netinet/in_var.h>
103#include <netinet/ip.h>
104#include <netinet/ip_var.h>
105#include <netinet/ip_icmp.h>
106
107#include <netinet6/nd6.h>
108#include <netinet6/in6_ifattach.h>
109
110#include <net/if_var.h>
111
112/*
113 * 外部関数の定義
114 */
115
116extern const char *itron_strerror (ER ercd);
117
118#ifdef _IP6_CFG
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->in6_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->in6_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->in6_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 memcpy(&fdr->addr, src, sizeof(T_IN6_ADDR));
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->in6_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->in6_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->in6_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->in6_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
695 /* プレフィックスリストから空きのプレフィックスエントリを探索する。*/
696 for (ix = NUM_ND6_PREFIX_ENTRY; ix --; ) {
697 pr = &nd6_prefix[ix];
698 if ((pr->flags & ND6_PREFIX_STATE_BUSY) == 0)
699 break;
700 }
701
702 /* プレフィックスリストに空きがなければエラー */
703 if (ix < 0)
704 return NULL;
705
706 pr->flags |= ND6_PREFIX_STATE_BUSY;
707
708 /* プレフィックスを追加する。*/
709 pr->prefix = pi->prefix;
710 pr->prefix_len = pi->prefix_len;
711
712 /* フラグを設定する。*/
713 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK) != 0)
714 pr->flags |= ND6_PREFIX_FLAG_ONLINK;
715 if ((pi->flags & ND_OPT_PI_FLAG_AUTO) != 0)
716 pr->flags |= ND6_PREFIX_FLAG_AUTO;
717
718 /* プレフィックスの有効時間を設定する。*/
719 pr->vltime = ntohl(pi->valid);
720 pr->pltime = ntohl(pi->preferred);
721 in6_init_prefix_ltimes(pr);
722
723 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) != 0) {
724 if (nd6_prefix_onlink(pr) != E_OK)
725 return NULL;
726 }
727
728 /* ルータマップを初期化する。*/
729 pr->routermap = 0;
730
731 /* ルータを追加する。*/
732 pfxrtr_add(pr - nd6_prefix, rtr_index);
733
734 return pr;
735 }
736
737/*
738 * prelist_update -- プレフィックス・リストを更新する。
739 */
740
741static void
742prelist_update (T_ND_OPT_PREFIX_INFO *pi, uint_t router_index)
743{
744 T_IFNET *ifp = IF_GET_IFNET();
745 T_ND6_PREFIX *pr;
746 T_IN6_IFADDR *ia = NULL;
747 int_t ix, ifidlen;
748
749 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
750 if ((pr = nd6_prefix_lookup(&pi->prefix, pi->prefix_len)) != NULL) {
751 /*
752 * 登録済みの場合は、プレフィックスリストを更新する。
753 */
754
755 /*
756 * フラグの更新の注意:
757 * on-link ビットと autonomous ビットは
758 * 1 から 0 に変更してはならない。
759 */
760
761 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK) != 0)
762 pr->flags |= ND6_PREFIX_FLAG_ONLINK;
763 if ((pi->flags & ND_OPT_PI_FLAG_AUTO) != 0)
764 pr->flags |= ND6_PREFIX_FLAG_AUTO;
765
766 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK) != 0) {
767 /*
768 * 通知されたプレフィックスがオンリンクの時は、
769 * 有効時間を更新する。
770 */
771 pr->vltime = ntohl(pi->valid);
772 pr->pltime = ntohl(pi->preferred);
773 in6_init_prefix_ltimes(pr);
774 }
775
776 if ((pi->flags & ND_OPT_PI_FLAG_ONLINK ) != 0 &&
777 (pr->flags & ND6_PREFIX_STATE_ONLINK) == 0) {
778 /*
779 * オフリンクのプレフィックスがオンリンクになった時の処理を実行する。
780 */
781 if (nd6_prefix_onlink(pr) != E_OK) {
782 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
783 syslog(LOG_ERROR, "[ND6 RTR] prefix update failed.");
784 return;
785 }
786 }
787
788 if (router_index != IN6_RTR_IX_UNREACH && pfxrtr_lookup(pr, router_index) == IN6_RTR_IX_UNREACH)
789 pfxrtr_add(pr - nd6_prefix, router_index);
790 }
791 else { /* 未登録の場合 */
792
793 /* 有効時間 0 のプレフィックスは追加しない。*/
794 if (pi->valid == 0) {
795 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
796 return;
797 }
798
799 /* オフリンクでアドレス自動設定に使用しなければ追加しない。*/
800 if ((pi->flags & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO)) !=
801 (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO)) {
802 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
803 return;
804 }
805
806 /* プレフィックスを追加する。*/
807 if ((pr = nd6_prelist_add(pi, router_index)) == NULL) {
808 syslog(LOG_ERROR, "[ND6 RTR] prefix add failed.");
809 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
810 return;
811 }
812
813#if 1 /* プレフィックスが未登録の場合だけ表示する。*/
814 syslog(LOG_NOTICE, "[ND6 RTR] add prefix: flags[MOH]: %02x, addr: %s\n"
815 " from: %s.",
816 nd6_def_router[router_index].flags,
817 ipv62str(NULL, &pi->prefix),
818 ipv62str(NULL, &nd6_def_router[router_index].addr));
819#endif
820 if ((pr->flags & ND6_PREFIX_FLAG_ONLINK) == 0) {
821 /*
822 * オフリンク・プレフィックスの場合は、有効時間を 0 に設定する。
823 * あとで有効期限切れとなり、リストから削除される。
824 */
825 pr->vltime = 0;
826 pr->pltime = 0;
827 in6_init_prefix_ltimes(pr);
828 }
829 }
830
831 /*
832 * ステートレス・アドレス自動設定を行う。
833 */
834 if ((pr->flags & ND6_PREFIX_FLAG_AUTO) == 0) {
835 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
836 return;
837 }
838
839 /*
840 * 通知されたプレフィックスが割り当てられているインタフェースの
841 * アドレス情報を探す。
842 */
843 for (ix = NUM_IN6_IFADDR_ENTRY; ix --; ) {
844 ia = &ifp->in6_ifaddrs[ix];
845 if ((ia->flags & IN6_IFF_DEFINED) != 0 &&
846 ia->prefix_len == pr->prefix_len &&
847 in6_are_prefix_equal(&ia->addr, &pr->prefix, pr->prefix_len))
848 break;
849 }
850
851 if (ix >= 0) { /* 登録済みのとき */
852 if ((ia->flags & IN6_IFF_AUTOCONF) == 0) {
853 /*
854 * ステートレス・アドレス自動設定により
855 * 設定されていなければ更新しない。
856 */
857 ;
858 }
859 else if (ia->flags & IN6_IFF_TENTATIVE) {
860 /*
861 * 重複検出中なら更新しない。
862 */
863 ;
864 }
865 else {
866 T_IN6_ADDR mask, addr;
867 T_IN6_IFADDR *lla;
868 uint32_t vltime;
869 SYSTIM now;
870 int_t ix;
871
872 /* 有効時間を設定する。*/
873 syscall(get_tim(&now));
874
875 if (ia->lifetime.vltime == ND6_INFINITE_LIFETIME)
876 vltime = ND6_INFINITE_LIFETIME;
877 else if (IFA6_IS_INVALID(ia, now))
878 vltime = 0;
879 else
880 vltime = ia->lifetime.expire - now / SYSTIM_HZ;
881
882 if (pr->vltime > (2 * 60 * 60) || pr->vltime > vltime) {
883 /*
884 * lifetime.expire、pi->valid (有効時間) と
885 * pi->preferred (推奨有効時間) の単位は [s]。
886 * 通知された有効時間が 2 時間以上か、現在の残り時間より
887 * 長ければ、新しい有効時間には、通知された有効時間を設定する。
888 */
889 vltime = pr->vltime;
890 }
891 else if (vltime <= (2 * 60 * 60))
892 ;
893 else {
894 /*
895 * IPsec は未実装のため、2 時間を設定する。
896 */
897 vltime = 2 * 60 * 60;
898 }
899
900 lla = &ifp->in6_ifaddrs[IPV6_IFADDR_IX_LINKLOCAL];
901
902 /* プレフィックスマスクを生成する。*/
903 in6_plen2pmask(&mask, pr->prefix_len);
904
905 /* アドレスを生成する。*/
906 for (ix = 0; ix < 4; ix ++)
907 addr.s6_addr32[ix] = (pr->prefix.s6_addr32[ix] & mask.s6_addr32[ix])
908 | ( lla->addr.s6_addr32[ix] & ~mask.s6_addr32[ix]);
909
910 in6_update_ifa(ifp, ia, &addr, pr->prefix_len, vltime,
911 pr->pltime, router_index, pr - nd6_prefix,
912 IN6_IFF_AUTOCONF | IN6_IFF_NODAD);
913 }
914 }
915
916 else { /* 未登録のとき */
917
918 /*
919 * プレフィックス長をチェックする。
920 * もし、プレフィックス長とインタフェース ID の合計が
921 * 128 ビットに一致しない時は、プレフィックス情報を無視する。
922 */
923 if ((ifidlen = in6_if2idlen(ifp)) < 0)
924 syslog(LOG_ERROR, "[ND6 RTR] IFID undefined.");
925 else if (ifidlen + pr->prefix_len != 128)
926 syslog(LOG_NOTICE, "[ND6 RTR] invalid prefix len: %d.", pr->prefix_len);
927 else {
928
929 for (ix = NUM_IN6_IFADDR_ENTRY; ix --; ) {
930 ia = &ifp->in6_ifaddrs[ix];
931 if ((ia->flags & IN6_IFF_DEFINED) == 0) {
932 in6_ifadd(pr, ia, router_index);
933 pfxlist_onlink_check();
934 break;
935 }
936 }
937
938 if (ix < 0)
939 syslog(LOG_ERROR, "[ND6 RTR] prefix update failed.");
940 }
941 }
942 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
943 }
944
945/*
946 * nd6_prelist_timer -- プレフィックス・リストの管理タイマー
947 */
948
949void
950nd6_prelist_timer (void)
951{
952 T_ND6_PREFIX *pr;
953 SYSTIM now;
954 int_t ix;
955
956 syscall(get_tim(&now));
957 now /= SYSTIM_HZ; /* 有効時間の単位は [s] */
958
959 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
960 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
961 pr = &nd6_prefix[ix];
962 if ((pr->flags & ND6_PREFIX_STATE_BUSY) != 0 && (int32_t)(pr->expire - now) <= 0)
963 /* pr->expire <= now */
964 prelist_remove(pr);
965 }
966 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
967 }
968
969/*
970 * nd6_rs_output -- ルータ要請を出力する。
971 */
972
973static void
974nd6_rs_output (void)
975{
976 T_ROUTER_SOLICIT_HDR *rsh;
977 T_NET_BUF *output;
978 T_IN6_IFADDR *ifa;
979 const T_IN6_ADDR *saddr;
980 uint16_t len;
981
982 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_RS_OUT_PACKETS], 1);
983
984 /*
985 * 送信元アドレスには、リンクローカルアドレスを設定するが、
986 * まだ設定されいなければ、無指定を設定する。
987 */
988 if ((ifa = in6ifa_ifpwithix(IF_GET_IFNET(), IPV6_IFADDR_IX_LINKLOCAL)) != NULL && !IFA6_IS_NOTREADY(ifa))
989 saddr = &ifa->addr;
990 else
991 saddr = &in6_addr_unspecified;
992
993 len = (ROUTER_SOLICIT_HDR_SIZE + 7) >> 3 << 3;
994
995 /* ネットワークバッファを獲得し、IPv6 ヘッダを設定する。*/
996 if (in6_get_datagram(&output, len, 0, &in6_addr_linklocal_allrouters,
997 saddr, IPPROTO_ICMPV6,
998 IPV6_MAXHLIM, NBA_SEARCH_ASCENT, TMO_ND6_RS_OUTPUT) != E_OK)
999 return;
1000
1001 /* ルータ要請ヘッダを設定する。*/
1002 rsh = GET_ROUTER_SOLICIT_HDR(output, IF_IP6_ROUTER_SOLICIT_HDR_OFFSET);
1003 rsh->hdr.type = ND_ROUTER_SOLICIT;
1004 rsh->hdr.code = 0;
1005 rsh->nd_rs_reserved = 0;
1006
1007 /* チェックサムを計算する。*/
1008 rsh->hdr.sum = 0;
1009 rsh->hdr.sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)rsh - output->buf, len);
1010
1011 /* 送信する。*/
1012 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_OCTETS],
1013 output->len - GET_IF_IP6_HDR_SIZE(output));
1014 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_PACKETS], 1);
1015 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
1016 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutRouterSolicits, 1);
1017 ip6_output(output, IPV6_OUT_SET_HOP_LIMIT(IPV6_OUT_FLG_HOP_LIMIT, IPV6_MAXHLIM), TMO_ND6_RS_OUTPUT);
1018 }
1019
1020/*
1021 * nd6_defrtrlist_lookup -- ディフォルトルータ・リストを探索する。
1022 */
1023
1024T_DEF_ROUTER *
1025nd6_defrtrlist_lookup (const T_IN6_ADDR *src)
1026{
1027 T_DEF_ROUTER *dr = NULL;
1028 int_t ix;
1029
1030 for (ix = def_router_count; ix -- > 0; ) {
1031 dr = &nd6_def_router[ix];
1032 if (IN6_ARE_ADDR_EQUAL(&dr->addr, src)) {
1033 return dr;
1034 }
1035 }
1036 return NULL;
1037 }
1038
1039/*
1040 * nd6_router_lookup -- ルータのアドレスを返す。
1041 *
1042 */
1043
1044const T_IN6_ADDR *
1045nd6_router_lookup (void)
1046{
1047 if (def_router_count > 0)
1048 return &nd6_def_router[0].addr;
1049 else
1050 return NULL;
1051 }
1052
1053/*
1054 * nd6_defrtrlist_del -- ディフォルトルータ・リストからルータを削除する。
1055 *
1056 * 注意: この関数を呼び出すときは、SEM_ND6_DEFRTRLIST で、
1057 * ロックしてから呼び出すこと。
1058 */
1059
1060void
1061nd6_defrtrlist_del (T_DEF_ROUTER *dr)
1062{
1063 T_IFNET *ifp = IF_GET_IFNET();
1064 T_IN6_IFADDR *ia;
1065 T_ND6_PREFIX *pr;
1066 uint_t mask;
1067 int_t ix, rix, pix, rtrix = dr - nd6_def_router;
1068
1069 if ((ia = in6ifa_ifpwithrtrix(ifp, rtrix)) != NULL) {
1070 /*
1071 * ネットワークインタフェースのプレフィックスを通知した
1072 * ルータを到達不能にする。
1073 */
1074 ia->router_index = IN6_RTR_IX_UNREACH;
1075 }
1076
1077 /* プレフィックスリストからルータを削除する。*/
1078 mask = make_mask(rtrix);
1079 for (pix = NUM_ND6_PREFIX_ENTRY; pix --; )
1080 nd6_prefix[pix].routermap &= ~mask;
1081
1082 /* 削除したルータ以降を前に詰める。*/
1083 for (rix = rtrix + 1; rix < def_router_count; rix ++)
1084 nd6_def_router[rix - 1] = nd6_def_router[rix];
1085
1086 /* プレフィックスリストのルータも更新する。*/
1087 if (dr != nd6_def_router) {
1088
1089 /* マスクを生成する。*/
1090 mask = 1;
1091 for (ix = rtrix - 1; ix -- > 0; )
1092 mask = (mask << 1) | 1;
1093
1094 for (pix = NUM_ND6_PREFIX_ENTRY; pix --; ) {
1095 pr = &nd6_prefix[pix];
1096 pr->routermap = (pr->routermap & mask) | (((pr->routermap & ~mask) >> 1) & ~mask);
1097 }
1098 }
1099 def_router_count --;
1100
1101 /* プレフィックスのオンリンク状態を確認する。*/
1102 pfxlist_onlink_check();
1103
1104 /*
1105 * 削除するルータが優先ディフォルトルータの場合は、
1106 * 優先ディフォルトルータを選択しなおす。
1107 */
1108 if (rtrix == 0)
1109 defrouter_select();
1110 }
1111
1112/*
1113 * nd6_defrtrlist_timer -- ディフォルトルータ・リストの管理タイマー
1114 */
1115
1116void
1117nd6_defrtrlist_timer (void)
1118{
1119 T_DEF_ROUTER *dr;
1120 SYSTIM now;
1121 int_t ix;
1122
1123 syscall(get_tim(&now));
1124
1125 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
1126 for (ix = def_router_count; ix -- > 0; ) {
1127 dr = &nd6_def_router[ix];
1128 if ((int32_t)(dr->expire - now) <= 0) {
1129 /* dr->expire <= now */
1130 nd6_defrtrlist_del(dr);
1131 }
1132 }
1133 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
1134 }
1135
1136/*
1137 * nd6_get_drl -- ディフォルトルータ・リストを獲得する。
1138 */
1139
1140const T_DEF_ROUTER *
1141nd6_get_drl (uint_t *count)
1142{
1143 *count = def_router_count;
1144 return nd6_def_router;
1145 }
1146
1147/*
1148 * nd6_get_prl -- プレフィックス・リストを獲得する。
1149 */
1150
1151const T_ND6_PREFIX *
1152nd6_get_prl (void)
1153{
1154 return nd6_prefix;
1155 }
1156
1157#endif /* of #if NUM_ND6_DEF_RTR_ENTRY > 0 */
1158
1159/*
1160 * nd6_ra_input -- ルータ通知の入力処理。
1161 */
1162
1163void
1164nd6_ra_input (T_NET_BUF *input, uint_t off)
1165{
1166#if NUM_ND6_DEF_RTR_ENTRY > 0
1167
1168 T_IFNET *ifp = IF_GET_IFNET();
1169 T_IP6_HDR *ip6h;
1170 T_ROUTER_ADVERT_HDR *rah;
1171 T_ND_OPT_HDR *opth;
1172 SYSTIM now;
1173 int_t rix;
1174 uint_t lladdr_len = 0;
1175 uint32_t advrea;
1176 uint8_t *lladdr = NULL;
1177 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
1178
1179 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_RA_IN_PACKETS], 1);
1180
1181 ip6h = GET_IP6_HDR(input);
1182
1183 /*
1184 * ヘッダのチェック、以下の場合は破棄する。
1185 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
1186 * ・ヘッダ長が短い
1187 * ・始点アドレスが、リンクローカルではない (RFC2461)
1188 */
1189 if (ip6h->hlim != IPV6_MAXHLIM ||
1190 input->len - off < ROUTER_ADVERT_HDR_SIZE ||
1191 !IN6_IS_ADDR_LINKLOCAL(&ip6h->src))
1192 goto err_ret;
1193
1194 rah = GET_ROUTER_ADVERT_HDR(input, off);
1195
1196 /* 近隣探索オプションのオフセットを記録する。*/
1197 if (nd6_options(nd_opt_off, input->buf + (off + ROUTER_ADVERT_HDR_SIZE),
1198 input->len - (off + ROUTER_ADVERT_HDR_SIZE)) != E_OK)
1199 goto err_ret;
1200 /*
1201 * 到達可能状態の有効時間の更新
1202
1203 */
1204 if (rah->reachable) {
1205 advrea = ntohl(rah->reachable) * SYSTIM_HZ / 1000; /* rah->reachable の単位は ms */
1206 if (advrea <= ND6_MAX_REACHABLE_TIME &&
1207 advrea != nd6_base_reachable_time) {
1208 syscall(get_tim(&now));
1209 nd6_recalc_reachtm_interval
1210 = now + ND6_RECALC_REACHTM_INTERVAL;
1211 nd6_base_reachable_time = advrea;
1212 nd6_reachable_time
1213 = ND6_CALC_REACH_TIME(nd6_base_reachable_time);
1214 }
1215 }
1216
1217 /* 近隣探索の送信間隔の更新 */
1218 if (rah->retransmit) {
1219 nd6_retrans_time = ntohl(rah->retransmit) * SYSTIM_HZ / 1000;
1220 /* rah->retransmit の単位は ms */
1221 }
1222
1223 /* ホップリミットの規定値の更新 */
1224 if (rah->nd_ra_current_hoplimit) {
1225 ip6_defhlim = rah->nd_ra_current_hoplimit;
1226 }
1227
1228 /* ディフォルトルータリストの更新 */
1229 rix = defrtrlist_update(&ip6h->src,
1230 ntohs(rah->nd_ra_router_lifetime),
1231 rah->nd_ra_flags); /* rah->nd_ra_router_lifetime の単位は秒 */
1232
1233 /* プレフィックスリストの更新 */
1234 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_PREFIX_INFO_COUNT)]) {
1235 T_ND_OPT_PREFIX_INFO *pi;
1236 uint_t pi_off, pi_count;
1237
1238 pi_count = nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_PREFIX_INFO_COUNT)];
1239 pi_off = off + ROUTER_ADVERT_HDR_SIZE
1240 + nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_PREFIX_INFORMATION)] - 8;
1241 /* 注意: オプションオフセット配列には、オフセット + 8 が設定されている。*/
1242 while (pi_count -- > 0) {
1243 pi = (T_ND_OPT_PREFIX_INFO*)(input->buf + pi_off);
1244 if (pi->type != ND_OPT_PREFIX_INFORMATION)
1245 /* オプションタイプがプレフィックス情報でなければ何もしない。*/
1246 ;
1247 else if (pi->len != 4)
1248 /* プレフィックス情報の長さが 32 (8×4) でなければ不正 */
1249 syslog(LOG_NOTICE, "[ND6 RTR] prefix opt len: %d.", pi->len);
1250 else if (pi->prefix_len > 128)
1251 /* プレフィックス長は 128 ビット以下 */
1252 syslog(LOG_NOTICE, "[ND6 RTR] prefix len: %d.", pi->prefix_len);
1253 else if (IN6_IS_ADDR_MULTICAST(&pi->prefix) ||
1254 IN6_IS_ADDR_LINKLOCAL(&pi->prefix))
1255 /* マルチキャストとリンクローカルは不正 */
1256 syslog(LOG_NOTICE, "[ND6 RTR] invalid addr: %s from %s.",
1257 ipv62str(NULL, &pi->prefix), ipv62str(NULL, &ip6h->src));
1258#if 0 /* FreeBSD 6.3 で削除されている。*/
1259 else if (IN6_IS_ADDR_AGGREGATE_UNICAST(&pi->prefix) &&
1260 (pi->prefix_len != 64) )
1261 /* 集約可能ユニキャストで、プレフィックス長が 64 ビット以外は不正 */
1262 syslog(LOG_NOTICE, "[ND6 RTR] invalid prefix len for global: %d.", pi->prefix_len);
1263#endif
1264 else if (ntohl(pi->preferred) > ntohl(pi->valid))
1265 /* 推奨有効時間が有効時間より長ければ不正 */
1266 syslog(LOG_NOTICE, "[ND6 RTR] preferred(%d) > valid time(%d).", ntohl(pi->preferred), ntohl(pi->valid));
1267 else {
1268#if 0 /* プレフィックスが未登録の場合だけ表示する。*/
1269 syslog(LOG_NOTICE, "[ND6 RTR] update prefix: flags[MOH]: %02x, addr: %s\n"
1270 " from: %s.",
1271 rah->nd_ra_flags, ipv62str(NULL, &pi->prefix), ipv62str(NULL, &ip6h->src));
1272#endif
1273 if (rix >= 0) {
1274 /*
1275 * defrtrlist_update の戻り値は、ルータのインデックス。
1276 * ただし、値が -1 なら、プレフィックス・リストは更新しない。
1277 */
1278 prelist_update(pi, rix); /* プレフィックス・リストを更新する。*/
1279 }
1280 }
1281 pi_off += pi->len << 3; /* オプション長の単位は 8 バイト */
1282 }
1283 }
1284
1285 /* MTU の更新 */
1286 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_MTU)]) {
1287 T_ND_OPT_MTU_HDR *optmtuh;
1288 uint32_t mtu;
1289
1290 optmtuh = (T_ND_OPT_MTU_HDR *)((uint8_t *)(input->buf + off + ROUTER_ADVERT_HDR_SIZE) +
1291 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_MTU)] - 8);
1292
1293 /*
1294 * 値のチェック
1295 *
1296 * オプション長: 1
1297 * 予約: 0
1298 */
1299 if (optmtuh->len != 1 || optmtuh->reserved != 0)
1300 goto err_ret;
1301
1302 /* MTU が IPv6 MMTU(1280 オクテット)以下なら無視する。*/
1303 mtu = ntohl(optmtuh->mtu);
1304 if (mtu >= IPV6_MMTU) {
1305 if (mtu <= (linkmtu > IF_MTU ? linkmtu : IF_MTU))
1306 linkmtu = mtu;
1307 }
1308 }
1309
1310 /*
1311 * ルータの始点リンクアドレスを近隣キャッシュに登録する。
1312 */
1313 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)]) {
1314 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + ROUTER_ADVERT_HDR_SIZE) +
1315 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)] - 8);
1316 /* 注意: オプションオフセット配列には、オフセット + 8 が設定されている。*/
1317 lladdr = (uint8_t *)(opth + 1);
1318 lladdr_len = (opth->len << 3);
1319 }
1320
1321 /*
1322 * ネットワークインタフェースのアドレス長が一致しなければエラー
1323 */
1324 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
1325 goto err_ret;
1326
1327 /* 近隣キャッシュに登録する。*/
1328 nd6_cache_lladdr(ifp, &ip6h->src, (T_IF_ADDR *)lladdr, ND_ROUTER_ADVERT, 0);
1329
1330 /*
1331 * ルータの始点リンクアドレスを近隣キャッシュに登録したので、
1332 * オンリンク状態が変化する可能性があるため、それをチェックする。
1333 */
1334 pfxlist_onlink_check();
1335
1336 syscall(rel_net_buf(input));
1337 return;
1338
1339err_ret:
1340 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
1341 syscall(rel_net_buf(input));
1342
1343#else /* of #if NUM_ND6_DEF_RTR_ENTRY > 0 */
1344
1345 /*
1346 * ルータ通知を受信しない場合は、破棄して終了する。
1347 */
1348 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_RA_IN_PACKETS], 1);
1349 syscall(rel_net_buf(input));
1350
1351#endif /* of #if NUM_ND6_DEF_RTR_ENTRY > 0 */
1352 }
1353
1354#if NUM_ND6_RTR_SOL_RETRY > 0
1355
1356/*
1357 * nd6_rtrsol_ctl -- ルータ要請出力の制御
1358 */
1359
1360void
1361nd6_rtrsol_ctl (void)
1362{
1363 T_IN6_IFADDR *ifa;
1364 int_t try;
1365
1366 /* リンクローカルアドレスのアドレス情報を得る。*/
1367 if ((ifa = in6ifa_ifpwithix(IF_GET_IFNET(), IPV6_IFADDR_IX_LINKLOCAL)) == NULL)
1368 return;
1369
1370 /* リンクローカルアドレスの重複検出終了を待つ。*/
1371 do {
1372 /* リンクローカルアドレスの重複検出終了待ち時間を設定する。*/
1373 syscall(dly_tsk(net_rand() % TMO_ND6_RTR_SOL_DELAY));
1374
1375 /* 待っている間に重複が検出されたら終了する。*/
1376 if (ifa->flags & IN6_IFF_DUPLICATED)
1377 return;
1378
1379 } while (!((ifa->flags & IN6_IFF_DEFINED) && (ifa->flags & IN6_IFF_TENTATIVE) == 0));
1380
1381 for (try = 0; try < NUM_ND6_RTR_SOL_RETRY; try ++) {
1382
1383 /* ディフォルトルータ・リストにエントリがあれば終了 */
1384 if (def_router_count > 0)
1385 return;
1386
1387 /* ルータ要請を出力する。*/
1388 nd6_rs_output();
1389
1390 /* 出力の 2 回目以降の遅延時間を設定する。*/
1391 syscall(dly_tsk(TMO_ND6_RTR_SOL_INTERVAL));
1392 }
1393 }
1394
1395#endif /* of #if NUM_ND6_RTR_SOL_RETRY > 0 */
1396
1397/*
1398 * nd6_onlink_prefix_lookup -- プレフィックスを探索する。
1399 */
1400
1401T_ND6_PREFIX *
1402nd6_onlink_prefix_lookup (const T_IN6_ADDR *dst)
1403{
1404 SYSTIM now;
1405 T_ND6_PREFIX *pr;
1406 int_t ix;
1407
1408 syscall(get_tim(&now));
1409 now /= SYSTIM_HZ;
1410
1411 /* 推奨有効時間内のプレフィックスを探索する。*/
1412 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
1413 pr = &nd6_prefix[ix];
1414 if ((pr->flags & ND6_PREFIX_STATE_BUSY) &&
1415 (pr->flags & ND6_PREFIX_FLAG_ONLINK) &&
1416 in6_are_prefix_equal(dst, &pr->prefix, pr->prefix_len) &&
1417 (int32_t)(pr->preferred - now) > 0) {
1418 /* pr->preferred > now */
1419 return pr;
1420 }
1421 }
1422
1423 /* 有効時間内のプレフィックスを探索する。*/
1424 for (ix = NUM_ND6_PREFIX_ENTRY; ix -- > 0; ) {
1425 pr = &nd6_prefix[ix];
1426 if ((pr->flags & ND6_PREFIX_STATE_BUSY) &&
1427 (pr->flags & ND6_PREFIX_FLAG_ONLINK) &&
1428 in6_are_prefix_equal(dst, &pr->prefix, pr->prefix_len) &&
1429 (int32_t)(pr->expire - now) > 0) {
1430 /* pr->expire > now */
1431 return pr;
1432 }
1433 }
1434
1435 return NULL;
1436 }
1437
1438#endif /* of #ifdef _IP6_CFG */
Note: See TracBrowser for help on using the repository browser.