source: azure_iot_hub/trunk/asp3_dcre/tinet/netinet6/nd6_nbr.c@ 388

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

Azure IoT Hub Device C SDK を使ったサンプルの追加

  • 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.4 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 * 上記著作権者
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 388 2019-05-22 11:25:18Z 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_endian.h>
108#include <net/net_var.h>
109#include <net/net_buf.h>
110#include <net/net_timer.h>
111#include <net/net_count.h>
112
113#include <netinet/in.h>
114#include <netinet/in_var.h>
115#include <netinet/ip.h>
116#include <netinet/ip_var.h>
117#include <netinet/ip_icmp.h>
118
119#include <netinet6/nd6.h>
120
121#include <net/if6_var.h>
122
123#ifdef _IP6_CFG
124
125/*
126 * 局所関数
127 */
128
129static void nd6_dad_timer (T_IN6_IFADDR *ifa);
130static void nd6_dad_duplicated (T_IFNET *ifp, T_IN6_IFADDR *ifa);
131static void nd6_dad_ns_output (T_IFNET *ifp, T_IN6_IFADDR *ifa);
132static void nd6_dad_ns_input (T_IFNET *ifp, T_IN6_IFADDR *ifa);
133static void nd6_dad_na_input (T_IFNET *ifp, T_IN6_IFADDR *ifa);
134
135/*
136 * nd6_dad_duplicated -- 重複アドレスを検出した時の処理
137 */
138
139static void
140nd6_dad_duplicated (T_IFNET *ifp, T_IN6_IFADDR *ifa)
141{
142 if ((ifa->flags & IN6_IFF_TENTATIVE) == 0)
143 syslog(LOG_ERROR, "[ND6 DAD DUP] no pending.");
144 else {
145 syslog(LOG_ERROR, "[ND6 DAD DUP] dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
146 ifa->flags &= ~IN6_IFF_TENTATIVE;
147 ifa->flags |= IN6_IFF_DUPLICATED;
148
149 /* タイマーを停止する。*/
150 untimeout((callout_func)nd6_dad_timer, ifa);
151
152 /*
153 * もし IPv6 アドレスが、ユニークに割り当てらた
154 * (イーサネット用の EUI-64)ハードウェアアドレスをベースとした
155 * インタフェース ID で生成されたのであれば、
156 * このインタフェースでの IPv6 の動作は無効にすべきである
157 * (RFC2462bis-03 セクション 5.4.5)。
158 */
159 if (IN6_IS_ADDR_LINKLOCAL(&ifa->addr))
160 ifp->flags |= ND6_IFF_IFDISABLED;
161 }
162 }
163
164/*
165 * nd6_dad_ns_output -- 重複アドレス検出 (DAD) 要請を出力する。
166 */
167
168static void
169nd6_dad_ns_output (T_IFNET *ifp, T_IN6_IFADDR *ifa)
170{
171 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_DAD_OUT_PACKETS], 1);
172
173 ifa->ns_ocount ++;
174 nd6_ns_output(ifp, &in6_addr_unspecified, &ifa->addr, NULL, true);
175 }
176
177/*
178 * nd6_dad_ns_input -- 重複アドレス検出 (DAD) 要請å…
179¥åŠ›
180 */
181
182static void
183nd6_dad_ns_input (T_IFNET *ifp, T_IN6_IFADDR *ifa)
184{
185 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_IN_PACKETS], 1);
186
187 /*
188 * まだ、重複アドレス検出要請を出力していない場合
189 */
190 if (ifa->ns_ocount == 0)
191 nd6_dad_duplicated(ifp, ifa);
192 else
193 ifa->ns_icount ++;
194 }
195
196/*
197 * nd6_dad_na_input -- 重複アドレス検出 (DAD) 通知å…
198¥åŠ›
199 */
200
201static void
202nd6_dad_na_input (T_IFNET *ifp, T_IN6_IFADDR *ifa)
203{
204 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NA_IN_PACKETS], 1);
205 ifa->na_icount ++;
206 nd6_dad_duplicated(ifp, ifa);
207 }
208
209/*
210 * nd6_dad_timer -- 重複アドレス検出 (DAD) タイマー
211 */
212
213static void
214nd6_dad_timer (T_IN6_IFADDR *ifa)
215{
216 T_IFNET *ifp = IF_GET_IFNET();
217
218 if (ifa->flags & IN6_IFF_DUPLICATED) {
219 syslog(LOG_ERROR, "[ND6 DAD] dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
220 return;
221 }
222
223 if ((ifa->flags & IN6_IFF_TENTATIVE) == 0) {
224 syslog(LOG_ERROR, "[ND6 DAD] no tentative IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
225 return;
226 }
227
228 if (ifa->ns_ocount < NUM_IP6_DAD_COUNT) {
229 nd6_dad_ns_output(ifp, ifa);
230
231 /* タイムアウトを近隣探索の送信間隔に設定する。*/
232 timeout((callout_func)nd6_dad_timer, ifa, ND6_RETRANS_TIME * NET_TIMER_HZ / SYSTIM_HZ);
233 }
234 else if (ifa->na_icount || ifa->ns_icount)
235 nd6_dad_duplicated(ifp, ifa);
236 else {
237 ifa->flags &= ~IN6_IFF_TENTATIVE;
238 syslog(LOG_NOTICE, "[ND6 DAD] no dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
239 }
240 }
241
242/*
243 * nd6_ns_input -- 近隣要請のå…
244¥åŠ›å‡¦ç†ã€‚
245 */
246
247void
248nd6_ns_input (T_NET_BUF *input, uint_t off)
249{
250 T_IFNET *ifp = IF_GET_IFNET();
251 T_IP6_HDR *ip6h;
252 T_NEIGHBOR_SOLICIT_HDR *nsh;
253 T_ND_OPT_HDR *opth;
254 T_IN6_IFADDR *ifa;
255 bool_t tlladdr;
256 uint_t lladdr_len = 0;
257 uint32_t flags;
258 uint8_t *lladdr = NULL;
259 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
260
261 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_IN_PACKETS], 1);
262
263 ip6h = GET_IP6_HDR(input);
264
265 /*
266 * ヘッダのチェック、以下の場合は破棄する。
267 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
268 * ・ヘッダ長が短い
269 */
270 if (ip6h->hlim != IPV6_MAXHLIM || input->len - off < NEIGHBOR_SOLICIT_HDR_SIZE)
271 goto err_ret;
272
273 nsh = (T_NEIGHBOR_SOLICIT_HDR *)(input->buf + off);
274
275 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src)) {
276 /*
277 * 始点アドレスが無指定なら、重複アドレス検出
278 * あてå…
279ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ã€è¦è«‹ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆã§ãªã‘ればならない。
280 */
281 if (!IN6_IS_ADDR_NS_MULTICAST(&ip6h->dst))
282 goto err_ret;
283 }
284
285 /* 目的アドレスがマルチキャストならエラー */
286 if (IN6_IS_ADDR_MULTICAST(&nsh->target))
287 goto err_ret;
288
289 /* 近隣探索オプションのオフセットを記録する。*/
290 if (nd6_options(nd_opt_off, input->buf + (off + NEIGHBOR_SOLICIT_HDR_SIZE),
291 input->len - (off + NEIGHBOR_SOLICIT_HDR_SIZE)) != E_OK)
292 goto err_ret;
293
294 /* 近隣探索オプション (始点リンクアドレス) */
295 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)]) {
296 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + NEIGHBOR_SOLICIT_HDR_SIZE) +
297 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_SOURCE_LINKADDR)] - 8);
298 /* 注意: オプションオフセットé…
299åˆ—には、オフセット + 8 が設定されている。*/
300 lladdr = (uint8_t *)(opth + 1);
301 lladdr_len = (opth->len << 3);
302 }
303
304 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src) && lladdr != NULL)
305 goto err_ret;
306
307 /* 宛å…
308ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆãªã‚‰è¿‘隣通知にデータリンク層のアドレスを付ける。*/
309 if (IN6_IS_ADDR_MULTICAST(&ip6h->dst))
310 tlladdr = true;
311 else
312 tlladdr = false;
313
314 /*
315 * 目的アドレスが、自分のネットワークインタフェースに
316 * 割り当てられているアドレスか調べる。
317 * なお、代理サービスは実装
318していない。
319 */
320 ifa = in6_lookup_ifaddr(ifp, &nsh->target);
321
322 if (ifa == NULL)
323 goto free_ret;
324
325 /* 探索結果アドレスが重複していれば応答しないで終了する。*/
326 if (ifa->flags & IN6_IFF_DUPLICATED)
327 goto err_ret;
328
329 /*
330 * ネットワークインタフェースのアドレス長が一致しなければエラー
331 */
332 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
333 goto err_ret;
334
335 /*
336 * 始点アドレスが自分のアドレスと一致すれば重複している。
337 */
338 if (IN6_ARE_ADDR_EQUAL(&ifa->addr, &ip6h->src))
339 goto free_ret;
340
341 /* 重複検出中に、近隣要請を受信したときの処理 */
342 if (ifa->flags & IN6_IFF_TENTATIVE) {
343 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src))
344 nd6_dad_ns_input(ifp, ifa);
345 goto free_ret;
346 }
347
348 if ((ifa->flags & IN6_IFF_ANYCAST) || !tlladdr)
349 flags = 0;
350 else
351 flags = ND_NA_FLG_OVERRIDE;
352
353 /*
354 * 始点アドレスが無指定なら、送信相手は重複アドレス検出中で、
355 * 直接送信することはできないので、å…
356¨ãƒŽãƒ¼ãƒ‰ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆ
357 * アドレスに送信する。
358 */
359 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src)) {
360 nd6_na_output(ifp, &in6_addr_linklocal_allnodes, &nsh->target, flags, tlladdr);
361 goto free_ret;
362 }
363
364 /* 近隣キャッシュに登録する。*/
365 nd6_cache_lladdr(ifp, &ip6h->src, (T_IF_ADDR *)lladdr, ND_NEIGHBOR_SOLICIT, 0);
366
367 nd6_na_output(ifp, &ip6h->src, &nsh->target, flags | ND_NA_FLG_SOLICITED, tlladdr);
368
369free_ret:
370 syscall(rel_net_buf(input));
371 return;
372
373err_ret:
374 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
375 syscall(rel_net_buf(input));
376 }
377
378/*
379 * nd6_ns_output -- 近隣要請を出力する。
380 */
381
382void
383nd6_ns_output (T_IFNET *ifp, const T_IN6_ADDR *daddr,
384 const T_IN6_ADDR *taddr, T_LLINFO_ND6 *ln, bool_t dad)
385{
386 T_NEIGHBOR_SOLICIT_HDR *nsh;
387 T_NET_BUF *output;
388 T_IP6_HDR *ip6h;
389 T_IF_ADDR *mac = NULL;
390 uint_t len;
391 uint16_t ipflags = 0;
392
393 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_OUT_PACKETS], 1);
394
395 if (IN6_IS_ADDR_MULTICAST(taddr))
396 return;
397
398 /* 近隣要請ペイロード長を計算する。*/
399 if (!dad && IF_SOFTC_TO_IFADDR(ifp->ic))
400 len = (NEIGHBOR_SOLICIT_HDR_SIZE + ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
401 else
402 len = (NEIGHBOR_SOLICIT_HDR_SIZE + 7) >> 3 << 3;
403
404 /*
405 * 要請マルチキャスト・アドレス宛の近隣探索では、
406 * 他のリンクからの偽造されたデータグラムを
407 * 排除するため、ホップリミットに IPV6_MAXHLIM (255) を設定する。
408 */
409 if (IN6_IS_ADDR_UNSPECIFIED(daddr) || IN6_IS_ADDR_MULTICAST(daddr))
410 ipflags = IPV6_OUT_SET_HOP_LIMIT(IPV6_OUT_FLG_HOP_LIMIT, IPV6_MAXHLIM);
411
412 /* ネットワークバッファを獲得し、IPv6 ヘッダを設定する。*/
413 if (in6_get_datagram(&output, len, 0, daddr, NULL,
414 IPPROTO_ICMPV6, IPV6_MAXHLIM,
415 NBA_SEARCH_ASCENT, TMO_ND6_NS_OUTPUT) != E_OK)
416 return;
417
418 ip6h = GET_IP6_HDR(output);
419
420 if (IN6_IS_ADDR_UNSPECIFIED(daddr)) {
421
422 /* 宛å…
423ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒç„¡æŒ‡å®šã®å ´åˆã¯ã€è¦è«‹ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’設定する。*/
424 ip6h->dst.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
425 ip6h->dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
426 ip6h->dst.s6_addr32[3] = taddr->s6_addr32[3];
427 ip6h->dst.s6_addr8[12] = 0xff;
428 }
429
430 /* 送信å…
431ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã®è¨­å®š */
432 if (!dad) {
433
434 /* 重複アドレス検出ではない時の送信å…
435ƒã‚¢ãƒ‰ãƒ¬ã‚¹æ±ºå®šå‡¦ç†ã€‚*/
436 T_IN6_ADDR *saddr;
437
438 if (ln && ln->hold) {
439 /*
440 * 送信がペンディングされているデータグラムの
441 * 送信å…
442ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’利用する。
443 */
444 if (ln->hold->len > IF_IP6_HDR_SIZE)
445 saddr = &GET_IP6_HDR(ln->hold)->src;
446 else
447 saddr = NULL;
448 }
449 else
450 saddr = NULL;
451
452 if (saddr && in6_lookup_ifaddr(ifp, saddr))
453 memcpy(&ip6h->src, saddr, sizeof(T_IN6_ADDR));
454 else {
455 /*
456 * 宛å…
457ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã«ãµã•ã‚ã—い送信å…
458ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’、
459 * ネットワークインタフェースから探索して利用する。
460 */
461 T_IN6_IFADDR *ifa;
462
463 if ((ifa = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
464 syscall(rel_net_buf(output));
465 return;
466 }
467 memcpy(&ip6h->src, &ifa->addr, sizeof(T_IN6_ADDR));
468 }
469 }
470 else {
471
472 /* 重複アドレス検出時の送信å…
473ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ç„¡æŒ‡å®šã€‚*/
474 memset(&ip6h->src, 0, sizeof(T_IN6_ADDR));
475 }
476
477 /* 近隣要請ヘッダを設定する。*/
478 nsh = GET_NEIGHBOR_SOLICIT_HDR(output, IF_IP6_NEIGHBOR_SOLICIT_HDR_OFFSET);
479 nsh->hdr.type = ND_NEIGHBOR_SOLICIT;
480 nsh->hdr.code = 0;
481 nsh->hdr.data.data32 = 0;
482 memcpy(&nsh->target, taddr, sizeof(T_IN6_ADDR));
483
484 if (!dad && (mac = IF_SOFTC_TO_IFADDR(ifp->ic)) != NULL) {
485
486 /* 近隣探索オプションとして、探索目標の MAC アドレスを設定する。*/
487 T_ND_OPT_HDR *opth;
488 uint_t optlen;
489
490 opth = (T_ND_OPT_HDR *)GET_NEIGHBOR_SOLICIT_SDU(output, IF_IP6_NEIGHBOR_SOLICIT_HDR_OFFSET);
491 optlen = (ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
492 memset(opth, 0, optlen);
493 opth->type = ND_OPT_SOURCE_LINKADDR;
494 opth->len = optlen >> 3;
495 memcpy((uint8_t *)opth + sizeof(T_ND_OPT_HDR), mac, sizeof(T_IF_ADDR));
496 }
497
498 /* チェックサムを計算する。*/
499 nsh->hdr.sum = 0;
500 nsh->hdr.sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)nsh - output->buf, len);
501
502 /* 送信する。*/
503 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_OCTETS],
504 output->len - GET_IF_IP6_HDR_SIZE(output));
505 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_PACKETS], 1);
506 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
507 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutNeighborSolicits, 1);
508 ip6_output(output, ipflags | IPV6_OUT_FLG_DAD, TMO_ND6_NS_OUTPUT);
509 }
510
511/*
512 * nd6_na_input -- 近隣通知のå…
513¥åŠ›å‡¦ç†ã€‚
514 */
515
516void
517nd6_na_input (T_NET_BUF *input, uint_t off)
518{
519 T_IFNET *ifp = IF_GET_IFNET();
520 T_IP6_HDR *ip6h;
521 T_NEIGHBOR_ADVERT_HDR *nah;
522 T_ND_OPT_HDR *opth;
523 T_IN6_IFADDR *ifa;
524 T_LLINFO_ND6 *ln;
525 SYSTIM now;
526 bool_t llchange;
527 uint_t lladdr_len = 0;
528 uint8_t *lladdr = NULL;
529 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
530
531 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NS_IN_PACKETS], 1);
532
533 ip6h = GET_IP6_HDR(input);
534
535 /*
536 * ヘッダのチェック、以下の場合は破棄する。
537 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
538 * ・ヘッダ長が短い
539 */
540 if (ip6h->hlim != IPV6_MAXHLIM || input->len - off < NEIGHBOR_ADVERT_HDR_SIZE)
541 goto err_ret;
542
543 nah = (T_NEIGHBOR_ADVERT_HDR *)(input->buf + off);
544
545 /* 目的アドレスがマルチキャストならエラー */
546 if (IN6_IS_ADDR_MULTICAST(&nah->target))
547 goto err_ret;
548
549 /* 近隣要請への応答で、宛å…
550ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆãªã‚‰ã‚¨ãƒ©ãƒ¼ */
551 if ((nah->nd_na_flags_reserved & ND_NA_FLG_SOLICITED) &&
552 IN6_IS_ADDR_MULTICAST(&ip6h->dst))
553 goto err_ret;
554
555 /* 近隣探索オプションのオフセットを記録する。*/
556 if (nd6_options(nd_opt_off, input->buf + (off + NEIGHBOR_ADVERT_HDR_SIZE),
557 input->len - (off + NEIGHBOR_ADVERT_HDR_SIZE)) != E_OK)
558 goto err_ret;
559
560 /* 近隣探索オプション (目的リンクアドレス) */
561 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)]) {
562 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + NEIGHBOR_ADVERT_HDR_SIZE) +
563 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)] - 8);
564 /* 注意: オプションオフセットé…
565åˆ—には、オフセット + 8 が設定されている。*/
566 lladdr = (uint8_t *)(opth + 1);
567 lladdr_len = (opth->len << 3);
568 }
569
570 ifa = in6_lookup_ifaddr(ifp, &nah->target);
571
572 /*
573 * 目的アドレスが自分のネットワークインタフェースに割り当てられているアドレスの
574 * いずれかに一致したときは、重複していることを意味している。
575 */
576 if (ifa) {
577 if (ifa->flags & IN6_IFF_TENTATIVE)
578 nd6_dad_na_input(ifp, ifa);
579 else
580 syslog(LOG_ERROR, "[ND6 NA INPUT] dup IPv6 addr: %s.", ipv62str(NULL, &ifa->addr));
581 goto err_ret;
582 }
583
584 /*
585 * ネットワークインタフェースのアドレス長が一致しなければエラー
586 */
587 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
588 goto err_ret;
589
590 /* 近隣キャッシュを探索する。*/
591 syscall(wai_sem(SEM_ND6_CACHE));
592 if ((ln = nd6_lookup(&nah->target, false)) == NULL)
593 goto free_ret;
594
595 /* 近隣キャッシュの状æ…
596‹ãŒã€ãƒ‡ãƒ¼ã‚¿ãƒªãƒ³ã‚¯å±¤ã®ã‚¢ãƒ‰ãƒ¬ã‚¹æœªè§£æ±ºã®å ´åˆ */
597 if (ln->state == ND6_LLINFO_INCOMPLETE) {
598 /* 通知されたデータリンク層のアドレスの長さが 0 の場合 */
599 if (lladdr == NULL)
600 goto free_ret;
601
602 ln->ifaddr = *(T_IF_ADDR *)lladdr;
603 if (nah->nd_na_flags_reserved & ND_NA_FLG_SOLICITED) {
604 ln->state = ND6_LLINFO_REACHABLE;
605 /*ln->byhint = 0*/;
606 if (ln->expire) {
607 syscall(get_tim(&now));
608 ln->expire = now + ND6_REACHABLE_TIME;
609 }
610 }
611 else {
612 syscall(get_tim(&now));
613 ln->expire = now + ND6_GCOLLECTION_TIME;
614 ln->state = ND6_LLINFO_STALE;
615 }
616
617 if ((nah->nd_na_flags_reserved & ND_NA_FLG_ROUTER) != 0)
618 ln->flags |= ND6_LLIF_ROUTER;
619 else
620 ln->flags &= ~ND6_LLIF_ROUTER;
621 if ((ln->flags & ND6_LLIF_ROUTER) != 0)
622 /*pfxlist_onlink_check()*/;
623 }
624 else {
625 if (lladdr == NULL)
626 llchange = false;
627 else if (memcmp(lladdr, &ln->ifaddr, sizeof(T_IF_ADDR)))
628 llchange = true;
629 else
630 llchange = false;
631
632 /*
633 * 状æ…
634‹é·ç§»è¡¨
635 *
636 * nd_na_flags_reserved
637 * OVERRIDE SOLICTED lladdr llchange 処理 (L: lladdr を登録する)
638 *
639 * F F N - (2c)
640 * F F Y F (2b) L
641 * F F Y T (1) REACHABLE -> STALE
642 * F T N - (2c) * -> REACHABLE
643 * F T Y F (2b) L * -> REACHABLE
644 * F T Y T (1) REACHABLE -> STALE
645 * T F N - (2a)
646 * T F Y F (2a) L
647 * T F Y T (2a) L *-> STALE
648 * T T N - (2a) * -> REACHABLE
649 * T T Y F (2a) L * -> REACHABLE
650 * T T Y T (2a) L * -> REACHABLE
651 */
652 if ((nah->nd_na_flags_reserved & ND_NA_FLG_OVERRIDE) == 0 && (lladdr != NULL && llchange)) { /* (1) */
653 /* 状æ…
654‹ãŒ REACHABLE なら STALE に遷移する。*/
655 if (ln->state == ND6_LLINFO_REACHABLE) {
656 syscall(get_tim(&now));
657 ln->expire = now + ND6_GCOLLECTION_TIME;
658 ln->state = ND6_LLINFO_STALE;
659 }
660 goto free_ret;
661 }
662 else if ((nah->nd_na_flags_reserved & ND_NA_FLG_OVERRIDE) || /* (2a) */
663 ((nah->nd_na_flags_reserved & ND_NA_FLG_OVERRIDE) == 0 && (lladdr != NULL && !llchange)) || /* (2b) */
664 lladdr == NULL) { /* (2c) */
665
666 /* データリンク層のアドレスが通知されていれば更新する。*/
667 if (lladdr != NULL)
668 ln->ifaddr = *(T_IF_ADDR *)lladdr;
669
670 /* 近隣要請への応答なら REACHABLE に遷移する。*/
671 if (nah->nd_na_flags_reserved & ND_NA_FLG_SOLICITED) {
672 ln->state = ND6_LLINFO_REACHABLE;
673 /*ln->byhint = 0*/;
674 if (ln->expire) {
675 syscall(get_tim(&now));
676 ln->expire = now + ND6_REACHABLE_TIME;
677 }
678 }
679 /*
680 * データリンク層のアドレスが通知され、
681 * 異なるアドレスなら更新する。
682 */
683 else if (lladdr != NULL && llchange) {
684 syscall(get_tim(&now));
685 ln->expire = now + ND6_GCOLLECTION_TIME;
686 ln->state = ND6_LLINFO_STALE;
687 }
688 }
689
690 /* ルータ通知フラグの処理 */
691 if ((ln->flags & ND6_LLIF_ROUTER ) != 0 &&
692 (nah->nd_na_flags_reserved & ND_NA_FLG_ROUTER) == 0) {
693 /*
694 * 送信相手がルータ通知フラグを無効にした場合。
695 * ディフォルト・ルータリストから対象のルータを削除し、
696 * 近隣探索キャッシュを更新する。
697 */
698 T_DEF_ROUTER *dr = NULL;
699
700 syscall(wai_sem(SEM_ND6_DEFRTRLIST));
701 if ((dr = nd6_defrtrlist_lookup(&ln->addr)) != NULL) {
702 nd6_defrtrlist_del(dr);
703 }
704 syscall(sig_sem(SEM_ND6_DEFRTRLIST));
705 }
706 if ((nah->nd_na_flags_reserved & ND_NA_FLG_ROUTER) != 0)
707 ln->flags |= ND6_LLIF_ROUTER;
708 else
709 ln->flags &= ~ND6_LLIF_ROUTER;
710 }
711
712 ln->asked = 0;
713
714 /* アドレス解決待
715ちのデータグラムがあれば送信する。*/
716 nd6_output_hold(ifp, ln);
717
718free_ret:
719 syscall(sig_sem(SEM_ND6_CACHE));
720 syscall(rel_net_buf(input));
721 return;
722
723err_ret:
724 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
725 syscall(rel_net_buf(input));
726 }
727
728/*
729 * nd6_na_output -- 近隣通知を出力する。
730 */
731
732void
733nd6_na_output (T_IFNET *ifp, const T_IN6_ADDR *daddr,
734 const T_IN6_ADDR *taddr, uint32_t flags, bool_t tlladdr)
735{
736 T_NEIGHBOR_ADVERT_HDR *nah;
737 T_NET_BUF *output;
738 T_IP6_HDR *ip6h;
739 T_IN6_IFADDR *ifa;
740 T_IF_ADDR *mac = NULL;
741 uint_t len;
742 uint16_t ipflags = 0;
743
744 NET_COUNT_ICMP6(net_count_nd6[NC_ND6_NA_OUT_PACKETS], 1);
745
746 /*
747 * 近隣通知ペイロード長を計算する。
748 * tlladdr が真ならネットワークインタフェースのアドレスを追加する。
749 */
750 if (tlladdr && IF_SOFTC_TO_IFADDR(ifp->ic))
751 len = (NEIGHBOR_ADVERT_HDR_SIZE + ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
752 else
753 len = (NEIGHBOR_ADVERT_HDR_SIZE + 7) >> 3 << 3;
754
755 /*
756 * 他のリンクからの偽造されたデータグラムを
757 * 排除するため、ホップリミットに IPV6_MAXHLIM (255) を設定する。
758 */
759 ipflags = IPV6_OUT_SET_HOP_LIMIT(IPV6_OUT_FLG_HOP_LIMIT, IPV6_MAXHLIM);
760
761 /* ネットワークバッファを獲得し、IPv6 ヘッダを設定する。*/
762 if (in6_get_datagram(&output, len, 0, daddr, NULL,
763 IPPROTO_ICMPV6, IPV6_MAXHLIM,
764 NBA_SEARCH_ASCENT, TMO_ND6_NA_OUTPUT) != E_OK)
765 return;
766
767 ip6h = GET_IP6_HDR(output);
768
769 if (IN6_IS_ADDR_UNSPECIFIED(daddr)) {
770 /*
771 * 宛å…
772ˆã‚¢ãƒ‰ãƒ¬ã‚¹ãŒç„¡æŒ‡å®šã®å ´åˆã¯ã€
773 * リンクローカルå…
774¨ãƒŽãƒ¼ãƒ‰ãƒ»ãƒžãƒ«ãƒã‚­ãƒ£ã‚¹ãƒˆã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’設定する。
775 */
776 ip6h->dst.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
777 ip6h->dst.s6_addr32[1] = 0;
778 ip6h->dst.s6_addr32[2] = 0;
779 ip6h->dst.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
780 flags &= ~ND_NA_FLG_SOLICITED;
781 }
782 else
783 memcpy(&ip6h->dst, daddr, sizeof(T_IN6_ADDR));
784
785 /*
786 * 宛å…
787ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã«ãµã•ã‚ã—い送信å…
788ƒã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’、
789 * ネットワークインタフェースから探索して利用する。
790 */
791 if ((ifa = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
792 syscall(rel_net_buf(output));
793 return;
794 }
795 memcpy(&ip6h->src, &ifa->addr, sizeof(T_IN6_ADDR));
796
797 /* 近隣通知ヘッダを設定する。*/
798 nah = GET_NEIGHBOR_ADVERT_HDR(output, IF_IP6_NEIGHBOR_ADVERT_HDR_OFFSET);
799 nah->hdr.type = ND_NEIGHBOR_ADVERT;
800 nah->hdr.code = 0;
801 memcpy(&nah->target, taddr, sizeof(T_IN6_ADDR));
802
803 /* tlladdr が真ならネットワークインタフェースのアドレスを追加する。*/
804 if (tlladdr && (mac = IF_SOFTC_TO_IFADDR(ifp->ic)) != NULL) {
805
806 T_ND_OPT_HDR *opth;
807 uint_t optlen;
808
809 opth = (T_ND_OPT_HDR *)GET_NEIGHBOR_ADVERT_SDU(output, IF_IP6_NEIGHBOR_ADVERT_HDR_OFFSET);
810 optlen = (ND_OPT_HDR_SIZE + sizeof(T_IF_ADDR) + 7) >> 3 << 3;
811 memset(opth, 0, optlen);
812 opth->type = ND_OPT_TARGET_LINKADDR;
813 opth->len = optlen >> 3;
814 memcpy((uint8_t *)opth + sizeof(T_ND_OPT_HDR), mac, sizeof(T_IF_ADDR));
815 }
816 else
817 flags &= ~ND_NA_FLG_OVERRIDE;
818
819 nah->nd_na_flags_reserved = flags;
820
821 /* チェックサムを計算する。*/
822 nah->hdr.sum = 0;
823 nah->hdr.sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)nah - output->buf, len);
824
825 /* 送信する。*/
826 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_OCTETS],
827 output->len - GET_IF_IP6_HDR_SIZE(output));
828 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_OUT_PACKETS], 1);
829 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
830 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutNeighborAdvertisements, 1);
831 ip6_output(output, ipflags, TMO_ND6_NS_OUTPUT);
832 }
833
834/*
835 * nd6_dad_start -- 重複アドレス検出 (DAD) を開始する。
836 *
837 * 第3引数のtick は、インタフェースが起動されてから、重複検出を
838 * 送信するまでの最小遅
839延値である。
840 */
841
842void
843nd6_dad_start (T_IFNET *ifp, T_IN6_IFADDR *ifa, int_t *tick)
844{
845 /* フラグをチェックする。*/
846 if (!(ifa->flags & IN6_IFF_TENTATIVE))
847 return;
848
849#if NUM_IP6_DAD_COUNT == 0
850
851 ifa->flags &= ~IN6_IFF_TENTATIVE;
852
853#else /* of #if NUM_IP6_DAD_COUNT == 0 */
854
855 if (ifa->flags & IN6_IFF_ANYCAST) {
856 ifa->flags &= ~IN6_IFF_TENTATIVE;
857 return;
858 }
859 else if ((ifa->flags & IN6_IFF_TENTATIVE) == 0)
860 return;
861
862 /* 重複アドレス検出カウンタをリセットする。*/
863 ifa->ns_icount = ifa->na_icount = ifa->ns_ocount = 0;
864
865 /*
866 * 重複アドレス検出要請を送信する。ただし、インタフェースを
867 * 初期化した直後に、最初に送信する場合は、ランダムな遅
868延を行う。
869 */
870 if (tick == NULL) {
871 nd6_dad_ns_output(ifp, ifa);
872
873 /* タイムアウトを近隣探索の送信間隔に設定する。*/
874 timeout((callout_func)nd6_dad_timer, ifa, ND6_RETRANS_TIME * NET_TIMER_HZ / SYSTIM_HZ);
875 }
876 else {
877 int_t ntick;
878
879 if (*tick == 0) /* 最初の送信 */
880 ntick = net_rand() % (ND6_FIRST_DAD_DELAY_TIME * NET_TIMER_HZ / SYSTIM_HZ);
881 else
882 ntick = *tick + net_rand() % (ND6_DAD_DELAY_TIME * NET_TIMER_HZ / SYSTIM_HZ);
883 *tick = ntick;
884 timeout((callout_func)nd6_dad_timer, ifa, ntick);
885 }
886
887#endif /* of #if NUM_IP6_DAD_COUNT == 0 */
888
889 }
890
891#endif /* of #ifdef _IP6_CFG */
Note: See TracBrowser for help on using the repository browser.