source: azure_iot_hub/trunk/asp3_dcre/tinet/netinet6/icmp6.c@ 389

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

ビルドが通るよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 22.3 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/icmp66.c,v 1.6.2.6 2001/07/10 09:44:16 ume Exp $ */
35/* $KAME: icmp66.c,v 1.211 2001/04/04 05:56:20 itojun 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/*
67 * Copyright (c) 1982, 1986, 1988, 1993
68 * The Regents of the University of California. All rights reserved.
69 *
70 * Redistribution and use in source and binary forms, with or without
71 * modification, are permitted provided that the following conditions
72 * are met:
73 * 1. Redistributions of source code must retain the above copyright
74 * notice, this list of conditions and the following disclaimer.
75 * 2. Redistributions in binary form must reproduce the above copyright
76 * notice, this list of conditions and the following disclaimer in the
77 * documentation and/or other materials provided with the distribution.
78 * 3. All advertising materials mentioning features or use of this software
79 * must display the following acknowledgement:
80 * This product includes software developed by the University of
81 * California, Berkeley and its contributors.
82 * 4. Neither the name of the University nor the names of its contributors
83 * may be used to endorse or promote products derived from this software
84 * without specific prior written permission.
85 *
86 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
87 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
88 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
89 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
90 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
91 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
92 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
93 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
94 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
95 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
96 * SUCH DAMAGE.
97 *
98 * @(#)ip_icmp6.c 8.2 (Berkeley) 1/4/94
99 */
100
101#include <string.h>
102
103#ifdef TARGET_KERNEL_ASP
104
105#include <kernel.h>
106#include <sil.h>
107#include <t_syslog.h>
108#include "tinet_cfg.h"
109
110#endif /* of #ifdef TARGET_KERNEL_ASP */
111
112#ifdef TARGET_KERNEL_JSP
113
114#include <s_services.h>
115#include <t_services.h>
116#include "tinet_id.h"
117
118#endif /* of #ifdef TARGET_KERNEL_JSP */
119
120#include <tinet_defs.h>
121#include <tinet_config.h>
122
123#include <net/if.h>
124#include <net/if_loop.h>
125#include <net/if_ppp.h>
126#include <net/ethernet.h>
127#include <net/net.h>
128#include <net/net_endian.h>
129#include <net/net_buf.h>
130#include <net/net_timer.h>
131#include <net/net_count.h>
132
133#include <netinet/in.h>
134#include <netinet/in_var.h>
135#include <netinet/ip.h>
136#include <netinet/ip_var.h>
137#include <netinet/ip_icmp.h>
138#include <netinet/tcp.h>
139#include <netinet/tcp_var.h>
140#include <netinet/udp_var.h>
141
142#include <netinet6/nd6.h>
143
144#ifdef _IP6_CFG
145
146/*
147 * 変数
148 */
149
150#ifdef SUPPORT_MIB
151
152/*
153 * SNMP の 管理情報ベース (MIB)
154 */
155
156T_ICMP6_IFSTAT icmp6_ifstat;
157
158#endif /* of #ifdef SUPPORT_MIB */
159
160/*
161 * icmp6_output -- ICMP6 パケットを送信する。
162 */
163
164static void
165icmp6_output (T_NET_BUF *output, uint_t off)
166{
167 T_IN6_IFADDR *ia;
168 T_IFNET *ifp = IF_GET_IFNET();
169 T_IP6_HDR *ip6h;
170 T_ICMP6_HDR *icmp6h;
171
172 /*
173 * 宛先アドレスにふさわしい送信元アドレスを、
174 * ネットワークインタフェースから探索して利用する。
175 */
176 ip6h = GET_IP6_HDR(output);
177 if ((ia = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
178 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutErrors, 1);
179 syscall(rel_net_buf(output));
180 return;
181 }
182 memcpy(&ip6h->src, &ia->addr, sizeof(T_IN6_ADDR));
183
184 icmp6h = GET_ICMP6_HDR(output, off);
185
186 /* チェックサムを計算する。*/
187 icmp6h->sum = 0;
188 icmp6h->sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)icmp6h - output->buf,
189 ntohs(ip6h->plen) - (off - IF_IP6_HDR_SIZE));
190
191 /* 送信する。*/
192 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_OCTETS],
193 output->len - GET_IF_IP6_HDR_SIZE(output));
194 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_PACKETS], 1);
195 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
196 ip6_output(output, 0, TMO_ICMP_OUTPUT);
197 }
198
199/*
200 * icmp6_echo_request -- エコー要求を受信したときの処理
201 */
202
203static void
204icmp6_echo_request (T_NET_BUF *input, uint_t off)
205{
206 T_IP6_HDR *ip6h;
207 T_ICMP6_HDR *icmp6h;
208 T_IFNET *ifp = IF_GET_IFNET();
209 T_IN6_IFADDR *ia;
210 T_IN6_ADDR dst;
211 uint_t diff;
212
213 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInEchos, 1);
214
215 ip6h = GET_IP6_HDR(input);
216
217 /*
218 * IPv6 ヘッダと ICMPv6 ヘッダ間の拡張ヘッダを除去する。
219 */
220 diff = off - IF_IP6_HDR_SIZE;
221 if (diff > 0) {
222 /* ICMPv6 ヘッダを前に詰める。*/
223 memmove(input->buf + IF_IP6_HDR_SIZE, input->buf + off, input->len - off);
224 off = IF_IP6_HDR_SIZE;
225
226 /* ペイロード長を調整する。*/
227 ip6h->plen = htons(ntohs(ip6h->plen) - diff);
228 input->len -= diff;
229 }
230
231 icmp6h = GET_ICMP6_HDR(input, off);
232 if (icmp6h->code != 0) {
233 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
234 syscall(rel_net_buf(input));
235 return;
236 }
237
238 /*
239 * メッセージの型をエコー要求 (128) から
240 * エコー応答 (129) に変更して送り返す。
241 */
242 icmp6h->type = ICMP6_ECHO_REPLY;
243
244 /* IPv6 ヘッダの発信元アドレスと宛先アドレスを入替える。*/
245 memcpy(&dst, &ip6h->dst, sizeof(T_IN6_ADDR));
246 memcpy(&ip6h->dst, &ip6h->src, sizeof(T_IN6_ADDR));
247 memcpy(&ip6h->src, &dst, sizeof(T_IN6_ADDR));
248
249 /*
250 * 元の宛先アドレスがマルチキャストの場合は、
251 * 宛先アドレスにふさわしい送信元アドレスを、
252 * ネットワークインタフェースから探索して利用する。
253 */
254 if (IN6_IS_ADDR_MULTICAST(&dst)) {
255 if ((ia = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
256 syscall(rel_net_buf(input));
257 return;
258 }
259 else
260 memcpy(&ip6h->src, &ia->addr, sizeof(T_IN6_ADDR));
261 }
262
263 /* 次ヘッダとホップリミットを設定する。*/
264 ip6h->next = IPPROTO_ICMPV6;
265 ip6h->hlim = IP6_DEFTTL;
266
267 /* チェックサムを計算する。*/
268 icmp6h->sum = 0;
269 icmp6h->sum = in6_cksum(input, IPPROTO_ICMPV6, (uint8_t*)icmp6h - input->buf,
270 ntohs(ip6h->plen) - (off - IF_IP6_HDR_SIZE));
271
272 /* 送信する。*/
273 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_OCTETS],
274 input->len - GET_IF_IP6_HDR_SIZE(input));
275 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_PACKETS], 1);
276 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
277 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutEchoReplies, 1);
278 ip6_output(input, 0, TMO_ICMP_OUTPUT);
279 }
280
281/*
282 * icmp6_notify_error -- エラーを通知する。
283 */
284
285static void
286icmp6_notify_error(T_NET_BUF *input, uint_t poff)
287{
288 T_ICMP6_HDR *icmp6h;
289 ER_UINT loff;
290 uint_t len, next;
291
292 len = input->len - poff;
293
294 /* データグラム長が ICMP6 ヘッダ長 + IP6 ヘッダ長以下なら何もしない。*/
295 if (len < ICMP6_HDR_SIZE + IP6_HDR_SIZE)
296 return;
297
298 icmp6h = GET_ICMP6_HDR(input, poff);
299
300 /* 最終ヘッダを探索する。*/
301 loff = ip6_lasthdr(input, poff + ICMP6_HDR_SIZE, IPPROTO_IPV6, &next);
302
303 /* 最終ヘッダが TCP/UDP のみ対応する。*/
304 if (loff >= 0 && (next == IPPROTO_TCP || next == IPPROTO_UDP)) {
305
306 memcpy(GET_IP6_HDR(input), input->buf + (loff + ICMP6_HDR_SIZE),
307 input->len - (loff + ICMP6_HDR_SIZE));
308 input->len -= loff + ICMP6_HDR_SIZE;
309
310#if defined(SUPPORT_TCP)
311
312 if (next == IPPROTO_TCP)
313
314 tcp_notify(input, icmp6h->code == ICMP6_DST_UNREACH_NOPORT ? EV_CNNRF : EV_HURCH);
315
316#endif /* of #if defined(SUPPORT_TCP) */
317
318#if defined(SUPPORT_UDP) && TNUM_UDP6_CEPID > 0
319
320 if (next == IPPROTO_UDP)
321
322 udp6_notify(input, icmp6h->code == ICMP6_DST_UNREACH_NOPORT ? EV_CNNRF : EV_HURCH);
323
324#endif /* of #if defined(SUPPORT_UDP) && TNUM_UDP6_CEPID > 0 */
325
326 }
327 else
328 syslog(LOG_NOTICE, "[ICMP6] error code: %d.", icmp6h->code);
329 }
330
331#if NUM_IN6_HOSTCACHE_ENTRY > 0
332
333/*
334 * icmp6_mtudisc_update -- Path MTU を更新する。
335 */
336
337static void
338icmp6_mtudisc_update(T_NET_BUF *input, uint_t off, uint32_t mtu)
339{
340 T_IP6_HDR *pip6h;
341
342 pip6h = (T_IP6_HDR*)GET_ICMP6_SDU(input, off);
343
344 if (mtu < IP6_HDR_SIZE + sizeof(T_IP6_FRAG_HDR) + 8)
345 return;
346
347 if (mtu > IF_MTU)
348 return;
349
350 in6_hostcache_update(&pip6h->dst, mtu);
351 }
352
353#endif /* of #if NUM_IN6_HOSTCACHE_ENTRY > 0 */
354
355#if defined(NUM_IN6_REDIRECT_ROUTE_ENTRY)
356#if NUM_IN6_REDIRECT_ROUTE_ENTRY > 0
357
358/*
359 * icmp6_redirect_input -- 向け直しメッセージの処理
360 */
361
362static void
363icmp6_redirect_input (T_NET_BUF *input, uint_t off)
364{
365 T_IP6_HDR *ip6h;
366 const T_IN6_ADDR *gw;
367 T_ND_REDIRECT_HDR *rdh;
368 T_ND_OPT_HDR *opth;
369 T_IFNET *ifp = IF_GET_IFNET();
370 bool_t router, onlink;
371 uint_t lladdr_len = 0;
372 uint8_t *lladdr = NULL;
373 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
374
375 ip6h = GET_IP6_HDR(input);
376
377 /*
378 * IP ヘッダのチェック、以下の場合は破棄する。
379 * ・リンクローカル以外から送られてきたメッセージ
380 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
381 */
382 if (!IN6_IS_ADDR_LINKLOCAL(&ip6h->src) || ip6h->hlim != IPV6_MAXHLIM)
383 goto err_ret;
384
385 rdh = (T_ND_REDIRECT_HDR *)(input->buf + off);
386
387 /* 向け直しの終点アドレスがマルチキャストアドレスの場合は破棄する。*/
388 if (IN6_IS_ADDR_MULTICAST(&rdh->dst))
389 goto err_ret;
390
391 /* ターゲットアドレスが経路表に登録されているかチェックする。*/
392 if ((gw = in6_rtalloc(ifp, &rdh->dst)) != NULL) {
393 /* GW アドレスと送信元アドレスが異なっていれば破棄する。*/
394 if (!IN6_ARE_ADDR_EQUAL(gw, &ip6h->src))
395 goto err_ret;
396 }
397 else /* 経路表になければ破棄する。*/
398 goto err_ret;
399
400 router = onlink = false;
401
402 /*
403 * ターゲットアドレスがリンクローカルアドレスであれば、
404 * ターゲットはルータ
405 */
406 if (IN6_IS_ADDR_LINKLOCAL(&rdh->target))
407 router = true;
408
409 /*
410 * ターゲットアドレスと終点アドレスが同一であれば、オンリンク
411 */
412 if (IN6_ARE_ADDR_EQUAL(&rdh->target, &rdh->dst))
413 onlink = true;
414
415 /*
416 * ルータでも、オンリンクでもなければエラー
417 */
418 if (!router && !onlink)
419 goto err_ret;
420
421 /* 近隣探索オプションのオフセットを記録する。*/
422 if (nd6_options(nd_opt_off, input->buf + off + ND_REDIRECT_HDR_SIZE,
423 input->len - (off + ND_REDIRECT_HDR_SIZE)) != E_OK)
424 goto err_ret;
425
426 /* 近隣探索オプション (向け直しのルータのリンクアドレス) */
427 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)]) {
428 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + ND_REDIRECT_HDR_SIZE) +
429 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)] - 8);
430 /* 注意: オプションオフセット配列には、オフセット + 8 が設定されている。*/
431 lladdr = (uint8_t *)(opth + 1);
432 lladdr_len = (opth->len << 3);
433 }
434
435 /*
436 * ネットワークインタフェースのアドレス長が一致しなければエラー
437 */
438 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
439 goto err_ret;
440
441 /* 向け直しのルータのリンクアドレスを近隣キャッシュに登録する。*/
442 nd6_cache_lladdr(ifp, &rdh->target, (T_IF_ADDR *)lladdr, ND_REDIRECT,
443 onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
444
445 /* ルーティング表に登録する。*/
446 in6_rtredirect(&rdh->target, &rdh->dst, 128, IN_RTF_REDIRECT, TMO_IN_REDIRECT);
447
448 syscall(rel_net_buf(input));
449 return;
450
451err_ret:
452 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
453 syscall(rel_net_buf(input));
454 }
455
456#endif /* of #if NUM_IN6_REDIRECT_ROUTE_ENTRY > 0 */
457#endif /* of #if defined(NUM_IN6_REDIRECT_ROUTE_ENTRY) */
458
459/*
460 * icmp6_input -- ICMP6 の入力関数
461 */
462
463uint_t
464icmp6_input (T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
465{
466 T_NET_BUF *input = *inputp;
467 T_IP6_HDR *ip6h;
468 T_ICMP6_HDR *icmp6h;
469 uint_t len, off = *offp;
470 uint8_t code;
471
472 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_OCTETS],
473 input->len - GET_IF_IP6_HDR_SIZE(input));
474 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_PACKETS], 1);
475 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInMsgs, 1);
476
477 /* ICMP6 ヘッダの長さをチェックする。*/
478 len = input->len - off;
479 if (len < ICMP6_HDR_SIZE) {
480 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
481 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInErrors, 1);
482 goto buf_rel;
483 }
484
485 ip6h = GET_IP6_HDR(input);
486 icmp6h = GET_ICMP6_HDR(input, off);
487
488 /* チェックサムを計算する。*/
489 if ((in6_cksum(input, IPPROTO_ICMPV6, off, ntohs(ip6h->plen) - (off - IF_IP6_HDR_SIZE)) & 0xffff) != 0) {
490 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
491 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInErrors, 1);
492 goto buf_rel;
493 }
494
495 code = icmp6h->code;
496
497 /* メッセージの型により分岐する。*/
498 switch (icmp6h->type) {
499
500 case ICMP6_DST_UNREACH: /* 宛先到達不可能 */
501 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInDestUnreachs, 1);
502 icmp6_notify_error(input, off);
503 break;
504
505 case ICMP6_ECHO_REQUEST: /* エコー要求 */
506 icmp6_echo_request(input, off);
507 return IPPROTO_DONE;
508 break;
509
510 case ICMP6_ECHO_REPLY: /* エコー応答 */
511
512#ifdef ICMP_CFG_CALLBACK_ECHO_REPLY
513
514 icmp6_echo_reply(input, off);
515
516#endif /* of #ifdef ICMP_CFG_CALLBACK_ECHO_REPLY */
517
518 break;
519
520 case ND_ROUTER_ADVERT: /* ルータ通知 */
521 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInRouterAdvertisements, 1);
522 if (code != 0 || len < ROUTER_ADVERT_HDR_SIZE)
523 goto buf_rel;
524 nd6_ra_input(input, off);
525 return IPPROTO_DONE;
526 break;
527
528 case ND_NEIGHBOR_SOLICIT: /* 近隣要請 */
529 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInNeighborSolicits, 1);
530 if (code != 0 || len < NEIGHBOR_SOLICIT_HDR_SIZE)
531 goto buf_rel;
532 nd6_ns_input(input, off);
533 return IPPROTO_DONE;
534 break;
535
536 case ND_NEIGHBOR_ADVERT: /* 近隣通知 */
537 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInNeighborAdvertisements, 1);
538 if (code != 0 || len < NEIGHBOR_ADVERT_HDR_SIZE)
539 goto buf_rel;
540 nd6_na_input(input, off);
541 return IPPROTO_DONE;
542 break;
543
544 case ND_REDIRECT: /* 向け直し */
545 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInRedirects, 1);
546
547#if defined(NUM_IN6_REDIRECT_ROUTE_ENTRY)
548#if NUM_IN6_REDIRECT_ROUTE_ENTRY > 0
549
550 if (code != 0 || len < ND_REDIRECT_HDR_SIZE)
551 goto buf_rel;
552 icmp6_redirect_input(input, off);
553 return IPPROTO_DONE;
554
555#else /* of #if NUM_IN6_REDIRECT_ROUTE_ENTRY > 0 */
556
557 syslog(LOG_WARNING, "[ICMP6] redirect ignored.");
558
559#endif /* of #if NUM_IN6_REDIRECT_ROUTE_ENTRY > 0 */
560#else /* of #if defined(NUM_IN6_REDIRECT_ROUTE_ENTRY) */
561
562 syslog(LOG_WARNING, "[ICMP6] redirect ignored.");
563
564#endif /* of #if defined(NUM_IN6_REDIRECT_ROUTE_ENTRY) */
565
566 break;
567
568 case ICMP6_PACKET_TOO_BIG: /* パケットが大きすぎる。 */
569
570#if NUM_IN6_HOSTCACHE_ENTRY > 0
571
572 icmp6_mtudisc_update(input, off, ntohl(icmp6h->icmp6_mtu));
573
574#endif /* of #if NUM_IN6_HOSTCACHE_ENTRY > 0 */
575
576 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInPktTooBigs, 1);
577 break;
578
579 case ICMP6_TIME_EXCEEDED: /* TTL を超過した。 */
580 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInTimeExcds, 1);
581 break;
582
583 case ICMP6_PARAM_PROB: /* IPv6 ヘッダが不正。 */
584 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInParmProblems, 1);
585 break;
586
587 case MLD_LISTENER_QUERY: /* マルチキャスト受信者照会 */
588 case MLD_LISTENER_REPORT: /* マルチキャスト受信者報告 */
589 case MLD_LISTENER_DONE: /* マルチキャスト受信者終了 */
590 case ND_ROUTER_SOLICIT: /* ルータ要請 */
591 case ICMP6_ROUTER_RENUMBERING: /* ルータ番号再設定 */
592 case ICMP6_FQDN_QUERY: /* FQDN 照会 */
593 case ICMP6_FQDN_REPLY: /* FQDN 応答 */
594 syslog(LOG_INFO, "[ICMP6] unsupported type: %d.", icmp6h->type);
595 break;
596
597 default:
598 syslog(LOG_WARNING, "[ICMP6] unknown type: %d.", icmp6h->type);
599 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
600 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInErrors, 1);
601 break;
602 }
603
604buf_rel:
605 syscall(rel_net_buf(input));
606 return IPPROTO_DONE;
607 }
608
609/*
610 * icmp6_error -- ICMP6 エラー送信関数
611 */
612
613void
614icmp6_error (T_NET_BUF *input, uint8_t type, uint8_t code, uint32_t param)
615{
616 T_NET_BUF *output;
617 T_IP6_HDR *ip6h;
618 T_ICMP6_HDR *icmp6h;
619 ER_UINT off;
620 uint_t next, len;
621
622 ip6h = GET_IP6_HDR(input);
623
624 /*
625 * 宛先アドレスが、マルチキャストの場合は、
626 * 以下の条件以外のときは処理を行わない。
627 *
628 * ・データグラムが大きすぎる。
629 * ・IPv6 ヘッダの不正で、オプションが認識できない。
630 */
631 if (IN6_IS_ADDR_MULTICAST(&ip6h->dst) &&
632 !((type == ICMP6_PACKET_TOO_BIG) ||
633 (type == ICMP6_PARAM_PROB && code == ICMP6_PARAMPROB_OPTION)))
634 goto buf_rel;
635
636 /*
637 * 始点アドレスが、以下の場合は処理を行わない。
638 *
639 * ・無指定
640 * ・マルチキャスト
641 */
642 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src) ||
643 IN6_IS_ADDR_MULTICAST (&ip6h->src))
644 goto buf_rel;
645
646 /* 最後のヘッダを探索する。*/
647 off = ip6_lasthdr(input, 0, IPPROTO_IPV6, &next);
648
649 /*
650 * タイプが、エラーか向け直しの ICMP6 パケットのエラーには返答しない。
651 */
652 if (off >= 0 && next == IPPROTO_ICMPV6) {
653 T_ICMP6_HDR *icmp6h;
654
655 if (input->len - off < ICMP6_HDR_SIZE)
656 goto buf_rel;
657
658 icmp6h = GET_ICMP6_HDR(input, off);
659 if (icmp6h->type < ICMP6_ECHO_REQUEST ||
660 icmp6h->type == ND_REDIRECT)
661 goto buf_rel;
662 }
663
664 /* DoS 攻撃に対する防御は未実装 */
665
666 /*
667 * 送り返すメッセージ長を、ICMPv6 の最大ペイロード長に調整する。
668 * IPV6_MMTU - (IP6_HDR_SIZE + ICMP6_HDR_SIZE)
669 */
670 if (input->len - IF_HDR_SIZE > IPV6_MMTU - (IP6_HDR_SIZE + ICMP6_HDR_SIZE))
671 len = IPV6_MMTU - (IP6_HDR_SIZE + ICMP6_HDR_SIZE);
672 else
673 len = input->len - IF_HDR_SIZE;
674
675 /* 送信用のネットワークバッファを獲得する。*/
676 if (in6_get_datagram(&output, len + ICMP6_HDR_SIZE, 0,
677 &ip6h->src, &in6_addr_unspecified,
678 IPPROTO_ICMPV6, IPV6_MAXHLIM,
679 NBA_SEARCH_ASCENT, TMO_ICMP_OUTPUT) != E_OK)
680 goto buf_rel;
681
682 /* ICMP6 ヘッダを設定する。*/
683 icmp6h = GET_ICMP6_HDR(output, IF_IP6_ICMP6_HDR_OFFSET);
684 icmp6h->type = type;
685 icmp6h->code = code;
686 icmp6h->icmp6_pptr = htonl(param);
687
688 /* エラーデータを設定する。*/
689 memcpy(GET_ICMP6_SDU(output, IF_IP6_ICMP6_HDR_OFFSET), (uint8_t *)ip6h, len);
690
691#ifdef SUPPORT_MIB
692
693 switch (type) {
694 case ICMP6_DST_UNREACH:
695 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutDestUnreachs, 1);
696 break;
697
698 case ICMP6_PARAM_PROB:
699 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutParmProblems, 1);
700 break;
701
702 default:
703 break;
704
705 }
706
707#endif /* of #ifdef SUPPORT_MIB */
708
709 /* 送信する。*/
710 icmp6_output(output, IF_IP6_HDR_SIZE);
711
712buf_rel:
713 syscall(rel_net_buf(input));
714 }
715
716#endif /* of #ifdef _IP6_CFG */
Note: See TracBrowser for help on using the repository browser.