source: EcnlProtoTool/trunk/asp3_dcre/tinet/netinet6/nd6_nbr.c@ 270

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

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 27.3 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 * 上記著作権者
8は,以下の (1)~(4) の条件か,Free Software Foundation
9 * によってå…
10¬è¡¨ã•ã‚Œã¦ã„ã‚‹ GNU General Public License の Version 2 に記
11 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
12 * を改変したものを含む.以下同じ)を使用・複製・改変・再é…
13å¸ƒï¼ˆä»¥ä¸‹ï¼Œ
14 * 利用と呼ぶ)することを無償で許諾する.
15 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
16 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
17 * スコード中に含まれていること.
18 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
19 * 用できる形で再é…
20å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œå†é…
21å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨
22 * 者
23マニュアルなど)に,上記の著作権表示,この利用条件および下記
24 * の無保証規定を掲載すること.
25 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
26 * 用できない形で再é…
27å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œæ¬¡ã®æ¡ä»¶ã‚’満たすこと.
28 * (a) 再é…
29å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨è€…
30マニュアルなど)に,上記の著
31 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
32 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
33 * 害からも,上記著作権者
34およびTOPPERSプロジェクトをå…
35è²¬ã™ã‚‹ã“と.
36 *
37 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者
38お
39 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
40 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
41 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
42 *
43 * @(#) $Id: nd6_nbr.c 270 2017-02-09 04:03:47Z coas-nagasima $
44 */
45
46/* $FreeBSD: src/sys/netinet6/nd6_nbr.c,v 1.13 2002/10/16 01:54:45 sam Exp $ */
47/* $KAME: nd6_nbr.c,v 1.86 2002/01/21 02:33:04 jinmei Exp $ */
48
49/*
50 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
51 * All rights reserved.
52 *
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions
55 * are met:
56 * 1. Redistributions of source code must retain the above copyright
57 * notice, this list of conditions and the following disclaimer.
58 * 2. Redistributions in binary form must reproduce the above copyright
59 * notice, this list of conditions and the following disclaimer in the
60 * documentation and/or other materials provided with the distribution.
61 * 3. Neither the name of the project nor the names of its contributors
62 * may be used to endorse or promote products derived from this software
63 * without specific prior written permission.
64 *
65 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
66 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
69 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75 * SUCH DAMAGE.
76 */
77
78#include <string.h>
79
80#ifdef TARGET_KERNEL_ASP
81
82#include <kernel.h>
83#include <sil.h>
84#include <t_syslog.h>
85#include "kernel_cfg.h"
86
87#endif /* of #ifdef TARGET_KERNEL_ASP */
88
89#ifdef TARGET_KERNEL_JSP
90
91#include <s_services.h>
92#include <t_services.h>
93#include "kernel_id.h"
94
95#endif /* of #ifdef TARGET_KERNEL_JSP */
96
97#include <tinet_defs.h>
98#include <tinet_config.h>
99
100#include <net/if.h>
101#include <net/if_ppp.h>
102#include <net/if_loop.h>
103#include <net/ethernet.h>
104#include <net/if_arp.h>
105#include <net/ppp_ipcp.h>
106#include <net/net.h>
107#include <net/net_var.h>
108#include <net/net_buf.h>
109#include <net/net_timer.h>
110#include <net/net_count.h>
111
112#include <netinet/in.h>
113#include <netinet/in_var.h>
114
115#include <netinet6/in6.h>
116#include <netinet6/in6_var.h>
117#include <netinet6/nd6.h>
118
119#include <netinet/ip6.h>
120#include <netinet/icmp6.h>
121#include <netinet6/ip6_var.h>
122
123#include <net/if6_var.h>
124
125#ifdef SUPPORT_INET6
126
127/*
128 * 局所関数
129 */
130
131static void nd6_dad_timer (T_IN6_IFADDR *ifa);
132static void nd6_dad_duplicated (T_IFNET *ifp, T_IN6_IFADDR *ifa);
133static void nd6_dad_ns_output (T_IFNET *ifp, T_IN6_IFADDR *ifa);
134static void nd6_dad_ns_input (T_IFNET *ifp, T_IN6_IFADDR *ifa);
135static void nd6_dad_na_input (T_IFNET *ifp, T_IN6_IFADDR *ifa);
136
137/*
138 * nd6_dad_duplicated -- 重複アドレスを検出した時の処理
139 */
140
141static void
142nd6_dad_duplicated (T_IFNET *ifp, T_IN6_IFADDR *ifa)
143{
144 if ((ifa->flags & IN6_IFF_TENTATIVE) == 0)
145 syslog(LOG_ERROR, "[ND6 DAD DUP] no pending.");
146 else {
147 syslog(LOG_ERROR, "[ND6 DAD DUP] dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
148 ifa->flags &= ~IN6_IFF_TENTATIVE;
149 ifa->flags |= IN6_IFF_DUPLICATED;
150
151 /* タイマーを停止する。*/
152 untimeout((callout_func)nd6_dad_timer, ifa);
153
154 /*
155 * もし IPv6 アドレスが、ユニークに割り当てらた
156 * (イーサネット用の EUI-64)ハードウェアアドレスをベースとした
157 * インタフェース ID で生成されたのであれば、
158 * このインタフェースでの IPv6 の動作は無効にすべきである
159 * (RFC2462bis-03 セクション 5.4.5)。
160 */
161 if (IN6_IS_ADDR_LINKLOCAL(&ifa->addr))
162 ifp->flags |= ND6_IFF_IFDISABLED;
163 }
164 }
165
166/*
167 * nd6_dad_ns_output -- 重複アドレス検出 (DAD) 要請を出力する。
168 */
169
170static void
171nd6_dad_ns_output (T_IFNET *ifp, T_IN6_IFADDR *ifa)
172{
173 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_DAD_OUT_PACKETS], 1);
174
175 ifa->ns_ocount ++;
176 nd6_ns_output(ifp, &in6_addr_unspecified, &ifa->addr, NULL, true);
177 }
178
179/*
180 * nd6_dad_ns_input -- 重複アドレス検出 (DAD) 要請å…
181¥åŠ›
182 */
183
184static void
185nd6_dad_ns_input (T_IFNET *ifp, T_IN6_IFADDR *ifa)
186{
187 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_IN_PACKETS], 1);
188
189 /*
190 * まだ、重複アドレス検出要請を出力していない場合
191 */
192 if (ifa->ns_ocount == 0)
193 nd6_dad_duplicated(ifp, ifa);
194 else
195 ifa->ns_icount ++;
196 }
197
198/*
199 * nd6_dad_na_input -- 重複アドレス検出 (DAD) 通知å…
200¥åŠ›
201 */
202
203static void
204nd6_dad_na_input (T_IFNET *ifp, T_IN6_IFADDR *ifa)
205{
206 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NA_IN_PACKETS], 1);
207 ifa->na_icount ++;
208 nd6_dad_duplicated(ifp, ifa);
209 }
210
211/*
212 * nd6_dad_timer -- 重複アドレス検出 (DAD) タイマー
213 */
214
215static void
216nd6_dad_timer (T_IN6_IFADDR *ifa)
217{
218 T_IFNET *ifp = IF_GET_IFNET();
219
220 if (ifa->flags & IN6_IFF_DUPLICATED) {
221 syslog(LOG_ERROR, "[ND6 DAD] dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
222 return;
223 }
224
225 if ((ifa->flags & IN6_IFF_TENTATIVE) == 0) {
226 syslog(LOG_ERROR, "[ND6 DAD] no tentative IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
227 return;
228 }
229
230 if (ifa->ns_ocount < NUM_IP6_DAD_COUNT) {
231 nd6_dad_ns_output(ifp, ifa);
232
233 /* タイムアウトを近隣探索の送信間隔に設定する。*/
234 timeout((callout_func)nd6_dad_timer, ifa, ND6_RETRANS_TIME * NET_TIMER_HZ / SYSTIM_HZ);
235 }
236 else if (ifa->na_icount || ifa->ns_icount)
237 nd6_dad_duplicated(ifp, ifa);
238 else {
239 ifa->flags &= ~IN6_IFF_TENTATIVE;
240 syslog(LOG_NOTICE, "[ND6 DAD] no dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
241 }
242 }
243
244/*
245 * nd6_ns_input -- 近隣要請のå…
246¥åŠ›å‡¦ç†ã€‚
247 */
248
249void
250nd6_ns_input (T_NET_BUF *input, uint_t off)
251{
252 T_IFNET *ifp = IF_GET_IFNET();
253 T_IP6_HDR *ip6h;
254 T_NEIGHBOR_SOLICIT_HDR *nsh;
255 T_ND_OPT_HDR *opth;
256 T_IN6_IFADDR *ifa;
257 bool_t tlladdr;
258 uint_t lladdr_len = 0;
259 uint32_t flags;
260 uint8_t *lladdr = NULL;
261 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
262
263 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_IN_PACKETS], 1);
264
265 ip6h = GET_IP6_HDR(input);
266
267 /*
268 * ヘッダのチェック、以下の場合は破棄する。
269 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
270 * ・ヘッダ長が短い
271 */
272 if (ip6h->hlim != IPV6_MAXHLIM || input->len - off < NEIGHBOR_SOLICIT_HDR_SIZE)
273 goto err_ret;
274
275 nsh = (T_NEIGHBOR_SOLICIT_HDR *)(input->buf + off);
276
277 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src)) {
278 /*
279 * 始点アドレスが無指定なら、重複アドレス検出
280 * あてå…
281ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ã€è¦è«‹ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆã§ãªã‘ればならない。
282 */
283 if (!IN6_IS_ADDR_NS_MULTICAST(&ip6h->dst))
284 goto err_ret;
285 }
286
287 /* 目的アドレスがマルチキャストならエラー */
288 if (IN6_IS_ADDR_MULTICAST(&nsh->target))
289 goto err_ret;
290
291 /* 近隣探索オプションのオフセットを記録する。*/
292 if (nd6_options(nd_opt_off, input->buf + (off + NEIGHBOR_SOLICIT_HDR_SIZE),
293 input->len - (off + NEIGHBOR_SOLICIT_HDR_SIZE)) != E_OK)
294 goto err_ret;
295
296 /* 近隣探索オプション (始点リンクアドレス) */
297 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)]) {
298 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + NEIGHBOR_SOLICIT_HDR_SIZE) +
299 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)] - 8);
300 /* 注意: オプションオフセットé…
301åˆ—には、オフセット + 8 が設定されている。*/
302 lladdr = (uint8_t *)(opth + 1);
303 lladdr_len = (opth->len << 3);
304 }
305
306 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src) && lladdr != NULL)
307 goto err_ret;
308
309 /* 宛å…
310ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆãªã‚‰è¿‘隣通知にデータリンク層のアドレスを付ける。*/
311 if (IN6_IS_ADDR_MULTICAST(&ip6h->dst))
312 tlladdr = true;
313 else
314 tlladdr = false;
315
316 /*
317 * 目的アドレスが、自分のネットワークインタフェースに
318 * 割り当てられているアドレスか調べる。
319 * なお、代理サービスは実装
320していない。
321 */
322 ifa = in6_lookup_ifaddr(ifp, &nsh->target);
323
324 if (ifa == NULL)
325 goto free_ret;
326
327 /* 探索結果アドレスが重複していれば応答しないで終了する。*/
328 if (ifa->flags & IN6_IFF_DUPLICATED)
329 goto err_ret;
330
331 /*
332 * ネットワークインタフェースのアドレス長が一致しなければエラー
333 */
334 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
335 goto err_ret;
336
337 /*
338 * 始点アドレスが自分のアドレスと一致すれば重複している。
339 */
340 if (IN6_ARE_ADDR_EQUAL(&ifa->addr, &ip6h->src))
341 goto free_ret;
342
343 /* 重複検出中に、近隣要請を受信したときの処理 */
344 if (ifa->flags & IN6_IFF_TENTATIVE) {
345 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src))
346 nd6_dad_ns_input(ifp, ifa);
347 goto free_ret;
348 }
349
350 if ((ifa->flags & IN6_IFF_ANYCAST) || !tlladdr)
351 flags = 0;
352 else
353 flags = ND_NA_FLG_OVERRIDE;
354
355 /*
356 * 始点アドレスが無指定なら、送信相手は重複アドレス検出中で、
357 * 直接送信することはできないので、å…
358¨ãƒŽãƒ¼ãƒ‰ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆ
359 * アドレスに送信する。
360 */
361 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src)) {
362 nd6_na_output(ifp, &in6_addr_linklocal_allnodes, &nsh->target, flags, tlladdr);
363 goto free_ret;
364 }
365
366 /* 近隣キャッシュに登録する。*/
367 nd6_cache_lladdr(ifp, &ip6h->src, (T_IF_ADDR *)lladdr, ND_NEIGHBOR_SOLICIT, 0);
368
369 nd6_na_output(ifp, &ip6h->src, &nsh->target, flags | ND_NA_FLG_SOLICITED, tlladdr);
370
371free_ret:
372 syscall(rel_net_buf(input));
373 return;
374
375err_ret:
376 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
377 syscall(rel_net_buf(input));
378 }
379
380/*
381 * nd6_ns_output -- 近隣要請を出力する。
382 */
383
384void
385nd6_ns_output (T_IFNET *ifp, T_IN6_ADDR *daddr,
386 T_IN6_ADDR *taddr, T_LLINFO_ND6 *ln, bool_t dad)
387{
388 T_NEIGHBOR_SOLICIT_HDR *nsh;
389 T_NET_BUF *output;
390 T_IP6_HDR *ip6h;
391 T_IF_ADDR *mac = NULL;
392 uint_t len;
393 uint16_t ipflags = 0;
394
395 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_OUT_PACKETS], 1);
396
397 if (IN6_IS_ADDR_MULTICAST(taddr))
398 return;
399
400 /* 近隣要請ペイロード長を計算する。*/
401 if (!dad && IF_SOFTC_TO_IFADDR(ifp->ic))
402 len = (NEIGHBOR_SOLICIT_HDR_SIZE + ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
403 else
404 len = (NEIGHBOR_SOLICIT_HDR_SIZE + 7) >> 3 << 3;
405
406 /*
407 * 要請マルチキャスト・アドレス宛の近隣探索では、
408 * 他のリンクからの偽造されたデータグラムを
409 * 排除するため、ホップリミットに IPV6_MAXHLIM (255) を設定する。
410 */
411 if (IN6_IS_ADDR_UNSPECIFIED(daddr) || IN6_IS_ADDR_MULTICAST(daddr))
412 ipflags = IPV6_OUT_SET_HOP_LIMIT(IPV6_OUT_FLG_HOP_LIMIT, IPV6_MAXHLIM);
413
414 /* ネットワークバッファを獲得し、IPv6 ヘッダを設定する。*/
415 if (in6_get_datagram(&output, len, 0, daddr, NULL,
416 IPPROTO_ICMPV6, IPV6_MAXHLIM,
417 NBA_SEARCH_ASCENT, TMO_ND6_NS_OUTPUT) != E_OK)
418 return;
419
420 ip6h = GET_IP6_HDR(output);
421
422 if (IN6_IS_ADDR_UNSPECIFIED(daddr)) {
423
424 /* 宛å…
425ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒç„¡æŒ‡å®šã®å ´åˆã¯ã€è¦è«‹ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’設定する。*/
426 ip6h->dst.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
427 ip6h->dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
428 ip6h->dst.s6_addr32[3] = taddr->s6_addr32[3];
429 ip6h->dst.s6_addr8[12] = 0xff;
430 }
431
432 /* 送信å…
433ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã®è¨­å®š */
434 if (!dad) {
435
436 /* 重複アドレス検出ではない時の送信å…
437ƒã‚¢ãƒ‰ãƒ¬ã‚¹æ±ºå®šå‡¦ç†ã€‚*/
438 T_IN6_ADDR *saddr;
439
440 if (ln && ln->hold) {
441 /*
442 * 送信がペンディングされているデータグラムの
443 * 送信å…
444ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’利用する。
445 */
446 if (ln->hold->len > IF_IP6_HDR_SIZE)
447 saddr = &GET_IP6_HDR(ln->hold)->src;
448 else
449 saddr = NULL;
450 }
451 else
452 saddr = NULL;
453
454 if (saddr && in6_lookup_ifaddr(ifp, saddr))
455 ip6h->src = *saddr;
456 else {
457 /*
458 * 宛å…
459ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã«ãµã•ã‚ã—い送信å…
460ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’、
461 * ネットワークインタフェースから探索して利用する。
462 */
463 T_IN6_IFADDR *ifa;
464
465 if ((ifa = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
466 syscall(rel_net_buf(output));
467 return;
468 }
469 ip6h->src = ifa->addr;
470 }
471 }
472 else {
473
474 /* 重複アドレス検出時の送信å…
475ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ç„¡æŒ‡å®šã€‚*/
476 memset(&ip6h->src, 0, sizeof(T_IN6_ADDR));
477 }
478
479 /* 近隣要請ヘッダを設定する。*/
480 nsh = GET_NEIGHBOR_SOLICIT_HDR(output, IF_IP6_NEIGHBOR_SOLICIT_HDR_OFFSET);
481 nsh->hdr.type = ND_NEIGHBOR_SOLICIT;
482 nsh->hdr.code = 0;
483 nsh->hdr.data.data32 = 0;
484 nsh->target = *taddr;
485
486 if (!dad && (mac = IF_SOFTC_TO_IFADDR(ifp->ic)) != NULL) {
487
488 /* 近隣探索オプションとして、探索目標の MAC アドレスを設定する。*/
489 T_ND_OPT_HDR *opth;
490 uint_t optlen;
491
492 opth = (T_ND_OPT_HDR *)GET_NEIGHBOR_SOLICIT_SDU(output, IF_IP6_NEIGHBOR_SOLICIT_HDR_OFFSET);
493 optlen = (ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
494 memset(opth, 0, optlen);
495 opth->type = ND_OPT_SOURCE_LINKADDR;
496 opth->len = optlen >> 3;
497 memcpy((uint8_t *)opth + sizeof(T_ND_OPT_HDR), mac, sizeof(T_IF_ADDR));
498 }
499
500 /* チェックサムを計算する。*/
501 nsh->hdr.sum = 0;
502 nsh->hdr.sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)nsh - output->buf, len);
503
504 /* 送信する。*/
505 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_OCTETS],
506 output->len - GET_IF_IP6_HDR_SIZE(output));
507 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_PACKETS], 1);
508 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
509 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutNeighborSolicits, 1);
510 ip6_output(output, ipflags | IPV6_OUT_FLG_DAD, TMO_ND6_NS_OUTPUT);
511 }
512
513/*
514 * nd6_na_input -- 近隣通知のå…
515¥åŠ›å‡¦ç†ã€‚
516 */
517
518void
519nd6_na_input (T_NET_BUF *input, uint_t off)
520{
521 T_IFNET *ifp = IF_GET_IFNET();
522 T_IP6_HDR *ip6h;
523 T_NEIGHBOR_ADVERT_HDR *nah;
524 T_ND_OPT_HDR *opth;
525 T_IN6_IFADDR *ifa;
526 T_LLINFO_ND6 *ln;
527 SYSTIM now;
528 bool_t llchange;
529 uint_t lladdr_len = 0;
530 uint8_t *lladdr = NULL;
531 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
532
533 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_IN_PACKETS], 1);
534
535 ip6h = GET_IP6_HDR(input);
536
537 /*
538 * ヘッダのチェック、以下の場合は破棄する。
539 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
540 * ・ヘッダ長が短い
541 */
542 if (ip6h->hlim != IPV6_MAXHLIM || input->len - off < NEIGHBOR_ADVERT_HDR_SIZE)
543 goto err_ret;
544
545 nah = (T_NEIGHBOR_ADVERT_HDR *)(input->buf + off);
546
547 /* 目的アドレスがマルチキャストならエラー */
548 if (IN6_IS_ADDR_MULTICAST(&nah->target))
549 goto err_ret;
550
551 /* 近隣要請への応答で、宛å…
552ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆãªã‚‰ã‚¨ãƒ©ãƒ¼ */
553 if ((nah->nd_na_flags_reserved & ND_NA_FLG_SOLICITED) &&
554 IN6_IS_ADDR_MULTICAST(&ip6h->dst))
555 goto err_ret;
556
557 /* 近隣探索オプションのオフセットを記録する。*/
558 if (nd6_options(nd_opt_off, input->buf + (off + NEIGHBOR_ADVERT_HDR_SIZE),
559 input->len - (off + NEIGHBOR_ADVERT_HDR_SIZE)) != E_OK)
560 goto err_ret;
561
562 /* 近隣探索オプション (目的リンクアドレス) */
563 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)]) {
564 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + NEIGHBOR_ADVERT_HDR_SIZE) +
565 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)] - 8);
566 /* 注意: オプションオフセットé…
567åˆ—には、オフセット + 8 が設定されている。*/
568 lladdr = (uint8_t *)(opth + 1);
569 lladdr_len = (opth->len << 3);
570 }
571
572 ifa = in6_lookup_ifaddr(ifp, &nah->target);
573
574 /*
575 * 目的アドレスが自分のネットワークインタフェースに割り当てられているアドレスの
576 * いずれかに一致したときは、重複していることを意味している。
577 */
578 if (ifa) {
579 if (ifa->flags & IN6_IFF_TENTATIVE)
580 nd6_dad_na_input(ifp, ifa);
581 else
582 syslog(LOG_ERROR, "[ND6 NA INPUT] dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
583 goto err_ret;
584 }
585
586 /*
587 * ネットワークインタフェースのアドレス長が一致しなければエラー
588 */
589 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
590 goto err_ret;
591
592 /* 近隣キャッシュを探索する。*/
593 syscall(wai_sem(SEM_ND6_CACHE));
594 if ((ln = nd6_lookup(&nah->target, false)) == NULL)
595 goto free_ret;
596
597 /* 近隣キャッシュの状æ…
598‹ãŒã€ãƒ‡ãƒ¼ã‚¿ãƒªãƒ³ã‚¯å±¤ã®ã‚¢ãƒ‰ãƒ¬ã‚¹æœªè§£æ±ºã®å ´åˆ */
599 if (ln->state == ND6_LLINFO_INCOMPLETE) {
600 /* 通知されたデータリンク層のアドレスの長さが 0 の場合 */
601 if (lladdr == NULL)
602 goto free_ret;
603
604 ln->ifaddr = *(T_IF_ADDR *)lladdr;
605 if (nah->nd_na_flags_reserved & ND_NA_FLG_SOLICITED) {
606 ln->state = ND6_LLINFO_REACHABLE;
607 /*ln->byhint = 0*/;
608 if (ln->expire) {
609 syscall(get_tim(&now));
610 ln->expire = now + ND6_REACHABLE_TIME;
611 }
612 }
613 else {
614 syscall(get_tim(&now));
615 ln->expire = now + ND6_GCOLLECTION_TIME;
616 ln->state = ND6_LLINFO_STALE;
617 }
618
619 if ((nah->nd_na_flags_reserved & ND_NA_FLG_ROUTER) != 0)
620 ln->flags |= ND6_LLIF_ROUTER;
621 else
622 ln->flags &= ~ND6_LLIF_ROUTER;
623 if ((ln->flags & ND6_LLIF_ROUTER) != 0)
624 /*pfxlist_onlink_check()*/;
625 }
626 else {
627 if (lladdr == NULL)
628 llchange = false;
629 else if (memcmp(lladdr, &ln->ifaddr, sizeof(T_IF_ADDR)))
630 llchange = true;
631 else
632 llchange = false;
633
634 /*
635 * 状æ…
636‹é·ç§»è¡¨
637 *
638 * nd_na_flags_reserved
639 * OVERRIDE SOLICTED lladdr llchange 処理 (L: lladdr を登録する)
640 *
641 * F F N - (2c)
642 * F F Y F (2b) L
643 * F F Y T (1) REACHABLE -> STALE
644 * F T N - (2c) * -> REACHABLE
645 * F T Y F (2b) L * -> REACHABLE
646 * F T Y T (1) REACHABLE -> STALE
647 * T F N - (2a)
648 * T F Y F (2a) L
649 * T F Y T (2a) L *-> STALE
650 * T T N - (2a) * -> REACHABLE
651 * T T Y F (2a) L * -> REACHABLE
652 * T T Y T (2a) L * -> REACHABLE
653 */
654 if ((nah->nd_na_flags_reserved & ND_NA_FLG_OVERRIDE) == 0 && (lladdr != NULL && llchange)) { /* (1) */
655 /* 状æ…
656‹ãŒ REACHABLE なら STALE に遷移する。*/
657 if (ln->state == ND6_LLINFO_REACHABLE) {
658 syscall(get_tim(&now));
659 ln->expire = now + ND6_GCOLLECTION_TIME;
660 ln->state = ND6_LLINFO_STALE;
661 }
662 goto free_ret;
663 }
664 else if ((nah->nd_na_flags_reserved & ND_NA_FLG_OVERRIDE) || /* (2a) */
665 ((nah->nd_na_flags_reserved & ND_NA_FLG_OVERRIDE) == 0 && (lladdr != NULL && !llchange)) || /* (2b) */
666 lladdr == NULL) { /* (2c) */
667
668 /* データリンク層のアドレスが通知されていれば更新する。*/
669 if (lladdr != NULL)
670 ln->ifaddr = *(T_IF_ADDR *)lladdr;
671
672 /* 近隣要請への応答なら REACHABLE に遷移する。*/
673 if (nah->nd_na_flags_reserved & ND_NA_FLG_SOLICITED) {
674 ln->state = ND6_LLINFO_REACHABLE;
675 /*ln->byhint = 0*/;
676 if (ln->expire) {
677 syscall(get_tim(&now));
678 ln->expire = now + ND6_REACHABLE_TIME;
679 }
680 }
681 /*
682 * データリンク層のアドレスが通知され、
683 * 異なるアドレスなら更新する。
684 */
685 else if (lladdr != NULL && llchange) {
686 syscall(get_tim(&now));
687 ln->expire = now + ND6_GCOLLECTION_TIME;
688 ln->state = ND6_LLINFO_STALE;
689 }
690 }
691
692 /* ルータ通知フラグの処理 */
693 if ((ln->flags & ND6_LLIF_ROUTER ) != 0 &&
694 (nah->nd_na_flags_reserved & ND_NA_FLG_ROUTER) == 0) {
695 /*
696 * 送信相手がルータ通知フラグを無効にした場合。
697 * ディフォルト・ルータリストから対象のルータを削除し、
698 * 近隣探索キャッシュを更新する。
699 */
700 T_DEF_ROUTER *dr = NULL;
701
702 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
703 if ((dr = nd6_defrtrlist_lookup(&ln->addr)) != NULL) {
704 nd6_defrtrlist_del(dr);
705 }
706 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
707 }
708 if ((nah->nd_na_flags_reserved & ND_NA_FLG_ROUTER) != 0)
709 ln->flags |= ND6_LLIF_ROUTER;
710 else
711 ln->flags &= ~ND6_LLIF_ROUTER;
712 }
713
714 ln->asked = 0;
715
716 /* アドレス解決待
717ちのデータグラムがあれば送信する。*/
718 nd6_output_hold(ifp, ln);
719
720free_ret:
721 syscall(sig_sem(SEM_ND6_CACHE));
722 syscall(rel_net_buf(input));
723 return;
724
725err_ret:
726 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
727 syscall(rel_net_buf(input));
728 }
729
730/*
731 * nd6_na_output -- 近隣通知を出力する。
732 */
733
734void
735nd6_na_output (T_IFNET *ifp, T_IN6_ADDR *daddr,
736 T_IN6_ADDR *taddr, uint32_t flags, bool_t tlladdr)
737{
738 T_NEIGHBOR_ADVERT_HDR *nah;
739 T_NET_BUF *output;
740 T_IP6_HDR *ip6h;
741 T_IN6_IFADDR *ifa;
742 T_IF_ADDR *mac = NULL;
743 uint_t len;
744 uint16_t ipflags = 0;
745
746 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NA_OUT_PACKETS], 1);
747
748 /*
749 * 近隣通知ペイロード長を計算する。
750 * tlladdr が真ならネットワークインタフェースのアドレスを追加する。
751 */
752 if (tlladdr && IF_SOFTC_TO_IFADDR(ifp->ic))
753 len = (NEIGHBOR_ADVERT_HDR_SIZE + ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
754 else
755 len = (NEIGHBOR_ADVERT_HDR_SIZE + 7) >> 3 << 3;
756
757 /*
758 * 他のリンクからの偽造されたデータグラムを
759 * 排除するため、ホップリミットに IPV6_MAXHLIM (255) を設定する。
760 */
761 ipflags = IPV6_OUT_SET_HOP_LIMIT(IPV6_OUT_FLG_HOP_LIMIT, IPV6_MAXHLIM);
762
763 /* ネットワークバッファを獲得し、IPv6 ヘッダを設定する。*/
764 if (in6_get_datagram(&output, len, 0, daddr, NULL,
765 IPPROTO_ICMPV6, IPV6_MAXHLIM,
766 NBA_SEARCH_ASCENT, TMO_ND6_NA_OUTPUT) != E_OK)
767 return;
768
769 ip6h = GET_IP6_HDR(output);
770
771 if (IN6_IS_ADDR_UNSPECIFIED(daddr)) {
772 /*
773 * 宛å…
774ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒç„¡æŒ‡å®šã®å ´åˆã¯ã€
775 * リンクローカルå…
776¨ãƒŽãƒ¼ãƒ‰ãƒ»ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’設定する。
777 */
778 ip6h->dst.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
779 ip6h->dst.s6_addr32[1] = 0;
780 ip6h->dst.s6_addr32[2] = 0;
781 ip6h->dst.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
782 flags &= ~ND_NA_FLG_SOLICITED;
783 }
784 else
785 ip6h->dst = *daddr;
786
787 /*
788 * 宛å…
789ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã«ãµã•ã‚ã—い送信å…
790ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’、
791 * ネットワークインタフェースから探索して利用する。
792 */
793 if ((ifa = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
794 syscall(rel_net_buf(output));
795 return;
796 }
797 ip6h->src = ifa->addr;
798
799 /* 近隣通知ヘッダを設定する。*/
800 nah = GET_NEIGHBOR_ADVERT_HDR(output, IF_IP6_NEIGHBOR_ADVERT_HDR_OFFSET);
801 nah->hdr.type = ND_NEIGHBOR_ADVERT;
802 nah->hdr.code = 0;
803 nah->target = *taddr;
804
805 /* tlladdr が真ならネットワークインタフェースのアドレスを追加する。*/
806 if (tlladdr && (mac = IF_SOFTC_TO_IFADDR(ifp->ic)) != NULL) {
807
808 T_ND_OPT_HDR *opth;
809 uint_t optlen;
810
811 opth = (T_ND_OPT_HDR *)GET_NEIGHBOR_ADVERT_SDU(output, IF_IP6_NEIGHBOR_ADVERT_HDR_OFFSET);
812 optlen = (ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
813 memset(opth, 0, optlen);
814 opth->type = ND_OPT_TARGET_LINKADDR;
815 opth->len = optlen >> 3;
816 memcpy((uint8_t *)opth + sizeof(T_ND_OPT_HDR), mac, sizeof(T_IF_ADDR));
817 }
818 else
819 flags &= ~ND_NA_FLG_OVERRIDE;
820
821 nah->nd_na_flags_reserved = flags;
822
823 /* チェックサムを計算する。*/
824 nah->hdr.sum = 0;
825 nah->hdr.sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)nah - output->buf, len);
826
827 /* 送信する。*/
828 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_OCTETS],
829 output->len - GET_IF_IP6_HDR_SIZE(output));
830 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_PACKETS], 1);
831 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
832 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutNeighborAdvertisements, 1);
833 ip6_output(output, ipflags, TMO_ND6_NS_OUTPUT);
834 }
835
836/*
837 * nd6_dad_start -- 重複アドレス検出 (DAD) を開始する。
838 *
839 * 第3引数のtick は、インタフェースが起動されてから、重複検出を
840 * 送信するまでの最小遅
841延値である。
842 */
843
844void
845nd6_dad_start (T_IFNET *ifp, T_IN6_IFADDR *ifa, int_t *tick)
846{
847 /* フラグをチェックする。*/
848 if (!(ifa->flags & IN6_IFF_TENTATIVE))
849 return;
850
851#if NUM_IP6_DAD_COUNT == 0
852
853 ifa->flags &= ~IN6_IFF_TENTATIVE;
854
855#else /* of #if NUM_IP6_DAD_COUNT == 0 */
856
857 if (ifa->flags & IN6_IFF_ANYCAST) {
858 ifa->flags &= ~IN6_IFF_TENTATIVE;
859 return;
860 }
861 else if ((ifa->flags & IN6_IFF_TENTATIVE) == 0)
862 return;
863
864 /* 重複アドレス検出カウンタをリセットする。*/
865 ifa->ns_icount = ifa->na_icount = ifa->ns_ocount = 0;
866
867 /*
868 * 重複アドレス検出要請を送信する。ただし、インタフェースを
869 * 初期化した直後に、最初に送信する場合は、ランダムな遅
870延を行う。
871 */
872 if (tick == NULL) {
873 nd6_dad_ns_output(ifp, ifa);
874
875 /* タイムアウトを近隣探索の送信間隔に設定する。*/
876 timeout((callout_func)nd6_dad_timer, ifa, ND6_RETRANS_TIME * NET_TIMER_HZ / SYSTIM_HZ);
877 }
878 else {
879 int_t ntick;
880
881 if (*tick == 0) /* 最初の送信 */
882 ntick = net_rand() % (ND6_FIRST_DAD_DELAY_TIME * NET_TIMER_HZ / SYSTIM_HZ);
883 else
884 ntick = *tick + net_rand() % (ND6_DAD_DELAY_TIME * NET_TIMER_HZ / SYSTIM_HZ);
885 *tick = ntick;
886 timeout((callout_func)nd6_dad_timer, ifa, ntick);
887 }
888
889#endif /* of #if NUM_IP6_DAD_COUNT == 0 */
890
891 }
892
893#endif /* of #ifdef SUPPORT_INET6 */
Note: See TracBrowser for help on using the repository browser.