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

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

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 21.5 KB
Line 
1/*
2 * TINET (TCP/IP Protocol Stack)
3 *
4 * Copyright (C) 2001-2009 by Dep. of Computer Science and Engineering
5 * Tomakomai National College of Technology, JAPAN
6 *
7 * 上記著作権者は,以下の (1)~(4) の条件か,Free Software Foundation
8 * によって公表されている GNU General Public License の Version 2 に記
9 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
10 * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
11 * 利用と呼ぶ)することを無償で許諾する.
12 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14 * スコード中に含まれていること.
15 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18 * の無保証規定を掲載すること.
19 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20 * 用できない形で再配布する場合には,次の条件を満たすこと.
21 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
22 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
23 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25 *
26 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
27 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
28 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
29 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
30 *
31 * @(#) $Id$
32 */
33
34/* $FreeBSD: src/sys/netinet6/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
109#endif /* of #ifdef TARGET_KERNEL_ASP */
110
111#ifdef TARGET_KERNEL_JSP
112
113#include <s_services.h>
114#include <t_services.h>
115
116#endif /* of #ifdef TARGET_KERNEL_JSP */
117
118#include <tinet_defs.h>
119#include <tinet_config.h>
120
121#include <net/if.h>
122#include <net/if_loop.h>
123#include <net/if_ppp.h>
124#include <net/ethernet.h>
125#include <net/net.h>
126#include <net/net_buf.h>
127#include <net/net_timer.h>
128#include <net/net_count.h>
129
130#include <netinet/in.h>
131#include <netinet/in_var.h>
132#include <netinet6/in6.h>
133#include <netinet6/in6_var.h>
134#include <netinet/ip6.h>
135#include <netinet6/ip6_var.h>
136#include <netinet/icmp6.h>
137#include <netinet6/nd6.h>
138#include <netinet/tcp.h>
139#include <netinet/tcp_timer.h>
140#include <netinet/tcp_var.h>
141
142#ifdef SUPPORT_INET6
143
144/*
145 * 変数
146 */
147
148#ifdef SUPPORT_MIB
149
150/*
151 * SNMP の 管理情報ベース (MIB)
152 */
153
154T_ICMP6_IFSTAT icmp6_ifstat;
155
156#endif /* of #ifdef SUPPORT_MIB */
157
158/*
159 * icmp6_output -- ICMP6 パケットを送信する。
160 */
161
162static void
163icmp6_output (T_NET_BUF *output, uint_t off)
164{
165 T_IN6_IFADDR *ia;
166 T_IFNET *ifp = IF_GET_IFNET();
167 T_IP6_HDR *ip6h;
168 T_ICMP6_HDR *icmp6h;
169
170 /*
171 * 宛先アドレスにふさわしい送信元アドレスを、
172 * ネットワークインタフェースから探索して利用する。
173 */
174 ip6h = GET_IP6_HDR(output);
175 if ((ia = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
176 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutErrors, 1);
177 syscall(rel_net_buf(output));
178 return;
179 }
180 ip6h->src = ia->addr;
181
182 icmp6h = GET_ICMP6_HDR(output, off);
183
184 /* チェックサムを計算する。*/
185 icmp6h->sum = 0;
186 icmp6h->sum = in6_cksum(output, IPPROTO_ICMPV6, (uint8_t*)icmp6h - output->buf,
187 ntohs(ip6h->plen) - (off - IF_IP6_HDR_SIZE));
188
189 /* 送信する。*/
190 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_OCTETS],
191 output->len - GET_IF_IP6_HDR_SIZE(output));
192 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_PACKETS], 1);
193 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
194 ip6_output(output, 0, TMO_ICMP_OUTPUT);
195 }
196
197/*
198 * icmp6_echo_request -- エコー要求を受信したときの処理
199 */
200
201static void
202icmp6_echo_request (T_NET_BUF *input, uint_t off)
203{
204 T_IP6_HDR *ip6h;
205 T_ICMP6_HDR *icmp6h;
206 T_IFNET *ifp = IF_GET_IFNET();
207 T_IN6_IFADDR *ia;
208 T_IN6_ADDR dst;
209 uint_t diff;
210
211 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInEchos, 1);
212
213 ip6h = GET_IP6_HDR(input);
214
215 /*
216 * IPv6 ヘッダと ICMPv6 ヘッダ間の拡張ヘッダを除去する。
217 */
218 diff = off - IF_IP6_HDR_SIZE;
219 if (diff > 0) {
220 /* ICMPv6 ヘッダを前に詰める。*/
221 memmove(input->buf + IF_IP6_HDR_SIZE, input->buf + off, input->len - off);
222 off = IF_IP6_HDR_SIZE;
223
224 /* ペイロード長を調整する。*/
225 ip6h->plen = htons(ntohs(ip6h->plen) - diff);
226 input->len -= diff;
227 }
228
229 icmp6h = GET_ICMP6_HDR(input, off);
230 if (icmp6h->code != 0) {
231 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
232 syscall(rel_net_buf(input));
233 return;
234 }
235
236 /*
237 * メッセージの型をエコー要求 (128) から
238 * エコー応答 (129) に変更して送り返す。
239 */
240 icmp6h->type = ICMP6_ECHO_REPLY;
241
242 /* IPv6 ヘッダの発信元アドレスと宛先アドレスを入替える。*/
243 dst = ip6h->dst;
244 ip6h->dst = ip6h->src;
245 ip6h->src = dst;
246
247 /*
248 * 元の宛先アドレスがマルチキャストの場合は、
249 * 宛先アドレスにふさわしい送信元アドレスを、
250 * ネットワークインタフェースから探索して利用する。
251 */
252 if (IN6_IS_ADDR_MULTICAST(&dst)) {
253 if ((ia = in6_ifawithifp(ifp, &ip6h->dst)) == NULL) {
254 syscall(rel_net_buf(input));
255 return;
256 }
257 else
258 ip6h->src = ia->addr;
259 }
260
261 /* 次ヘッダとホップリミットを設定する。*/
262 ip6h->next = IPPROTO_ICMPV6;
263 ip6h->hlim = IP_DEFTTL;
264
265 /* チェックサムを計算する。*/
266 icmp6h->sum = 0;
267 icmp6h->sum = in6_cksum(input, IPPROTO_ICMPV6, (uint8_t*)icmp6h - input->buf,
268 ntohs(ip6h->plen) - (off - IF_IP6_HDR_SIZE));
269
270 /* 送信する。*/
271 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_OCTETS],
272 input->len - GET_IF_IP6_HDR_SIZE(input));
273 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_OUT_PACKETS], 1);
274 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutMsgs, 1);
275 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutEchoReplies, 1);
276 ip6_output(input, 0, TMO_ICMP_OUTPUT);
277 }
278
279/*
280 * icmp6_notify_error -- エラーを通知する。
281 */
282
283static void
284icmp6_notify_error(T_NET_BUF *input, uint_t poff)
285{
286 T_ICMP6_HDR *icmp6h;
287 ER_UINT loff;
288 uint_t len, next;
289
290 len = input->len - poff;
291
292 /* データグラム長が ICMP6 ヘッダ長 + IP6 ヘッダ長以下なら何もしない。*/
293 if (len < ICMP6_HDR_SIZE + IP6_HDR_SIZE)
294 return;
295
296 icmp6h = GET_ICMP6_HDR(input, poff);
297
298 /* 最終ヘッダを探索する。*/
299 loff = ip6_lasthdr(input, poff + ICMP6_HDR_SIZE, IPPROTO_IPV6, &next);
300
301 /* 最終ヘッダが TCP のみ対応する。*/
302 if (loff >= 0 && next == IPPROTO_TCP) {
303
304#ifdef SUPPORT_TCP
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 tcp_notify(input, icmp6h->code == ICMP6_DST_UNREACH_NOPORT ? EV_CNNRF : EV_HURCH);
310
311#endif /* of #ifdef SUPPORT_TCP */
312
313 }
314 else
315 syslog(LOG_NOTICE, "[ICMP6] error code: %d.", icmp6h->code);
316 }
317
318#if NUM_IN6_HOSTCACHE_ENTRY > 0
319
320/*
321 * icmp6_mtudisc_update -- Path MTU を更新する。
322 */
323
324static void
325icmp6_mtudisc_update(T_NET_BUF *input, uint_t off, uint32_t mtu)
326{
327 T_IP6_HDR *pip6h;
328
329 pip6h = (T_IP6_HDR*)GET_ICMP6_SDU(input, off);
330
331 if (mtu < IP6_HDR_SIZE + sizeof(T_IP6_FRAG_HDR) + 8)
332 return;
333
334 if (mtu > IF_MTU)
335 return;
336
337 in6_hostcache_update(&pip6h->dst, mtu);
338 }
339
340#endif /* of #if NUM_IN6_HOSTCACHE_ENTRY > 0 */
341
342#if NUM_REDIRECT_ROUTE_ENTRY > 0
343
344/*
345 * icmp6_redirect_input -- 向け直しメッセージの処理
346 */
347
348static void
349icmp6_redirect_input (T_NET_BUF *input, uint_t off)
350{
351 T_IP6_HDR *ip6h;
352 T_IN6_ADDR *gw;
353 T_ND_REDIRECT_HDR *rdh;
354 T_ND_OPT_HDR *opth;
355 T_IFNET *ifp = IF_GET_IFNET();
356 bool_t router, onlink;
357 uint_t lladdr_len = 0;
358 uint8_t *lladdr = NULL;
359 uint8_t nd_opt_off[ND_OPT_OFF_ARRAY_SIZE];
360
361 ip6h = GET_IP6_HDR(input);
362
363 /*
364 * IP ヘッダのチェック、以下の場合は破棄する。
365 * ・リンクローカル以外から送られてきたメッセージ
366 * ・ホップリミットが IPV6_MAXHLIM (255) 以外
367 */
368 if (!IN6_IS_ADDR_LINKLOCAL(&ip6h->src) || ip6h->hlim != IPV6_MAXHLIM)
369 goto err_ret;
370
371 rdh = (T_ND_REDIRECT_HDR *)(input->buf + off);
372
373 /* 向け直しの終点アドレスがマルチキャストアドレスの場合は破棄する。*/
374 if (IN6_IS_ADDR_MULTICAST(&rdh->dst))
375 goto err_ret;
376
377 /* ターゲットアドレスが経路表に登録されているかチェックする。*/
378 if ((gw = in6_rtalloc(ifp, &rdh->dst)) != NULL) {
379 /* GW アドレスと送信元アドレスが異なっていれば破棄する。*/
380 if (!IN6_ARE_ADDR_EQUAL(gw, &ip6h->src))
381 goto err_ret;
382 }
383 else /* 経路表になければ破棄する。*/
384 goto err_ret;
385
386 router = onlink = false;
387
388 /*
389 * ターゲットアドレスがリンクローカルアドレスであれば、
390 * ターゲットはルータ
391 */
392 if (IN6_IS_ADDR_LINKLOCAL(&rdh->target))
393 router = true;
394
395 /*
396 * ターゲットアドレスと終点アドレスが同一であれば、オンリンク
397 */
398 if (IN6_ARE_ADDR_EQUAL(&rdh->target, &rdh->dst))
399 onlink = true;
400
401 /*
402 * ルータでも、オンリンクでもなければエラー
403 */
404 if (!router && !onlink)
405 goto err_ret;
406
407 /* 近隣探索オプションのオフセットを記録する。*/
408 if (nd6_options(nd_opt_off, input->buf + off + ND_REDIRECT_HDR_SIZE,
409 input->len - (off + ND_REDIRECT_HDR_SIZE)) != E_OK)
410 goto err_ret;
411
412 /* 近隣探索オプション (向け直しのルータのリンクアドレス) */
413 if (nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)]) {
414 opth = (T_ND_OPT_HDR *)((uint8_t *)(input->buf + off + ND_REDIRECT_HDR_SIZE) +
415 nd_opt_off[ND_OPT_OFF_ARRAY_IX(ND_OPT_TARGET_LINKADDR)] - 8);
416 /* 注意: オプションオフセット配列には、オフセット + 8 が設定されている。*/
417 lladdr = (uint8_t *)(opth + 1);
418 lladdr_len = (opth->len << 3);
419 }
420
421 /*
422 * ネットワークインタフェースのアドレス長が一致しなければエラー
423 */
424 if (lladdr && lladdr_len != ((sizeof(T_IF_ADDR) + sizeof(T_ND_OPT_HDR) + 7) & ~7))
425 goto err_ret;
426
427 /* 向け直しのルータのリンクアドレスを近隣キャッシュに登録する。*/
428 nd6_cache_lladdr(ifp, &rdh->target, (T_IF_ADDR *)lladdr, ND_REDIRECT,
429 onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
430
431 /* ルーティング表に登録する。*/
432 in6_rtredirect(&rdh->target, &rdh->dst, 128, IN_RTF_REDIRECT, TMO_IN_REDIRECT);
433
434 syscall(rel_net_buf(input));
435 return;
436
437err_ret:
438 NET_COUNT_ICMP6(net_count_nd6[NC_ICMP6_IN_ERR_PACKETS], 1);
439 syscall(rel_net_buf(input));
440 }
441
442#endif /* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */
443
444/*
445 * icmp6_input -- ICMP6 の入力関数
446 */
447
448uint_t
449icmp6_input (T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
450{
451 T_NET_BUF *input = *inputp;
452 T_IP6_HDR *ip6h;
453 T_ICMP6_HDR *icmp6h;
454 uint_t len, off = *offp;
455 uint8_t code;
456
457 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_OCTETS],
458 input->len - GET_IF_IP6_HDR_SIZE(input));
459 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_PACKETS], 1);
460 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInMsgs, 1);
461
462 /* ICMP6 ヘッダの長さをチェックする。*/
463 len = input->len - off;
464 if (len < ICMP6_HDR_SIZE) {
465 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
466 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInErrors, 1);
467 goto buf_rel;
468 }
469
470 ip6h = GET_IP6_HDR(input);
471 icmp6h = GET_ICMP6_HDR(input, off);
472
473 /* チェックサムを計算する。*/
474 if ((in6_cksum(input, IPPROTO_ICMPV6, off, ntohs(ip6h->plen) - (off - IF_IP_HDR_SIZE)) & 0xffff) != 0) {
475 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
476 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInErrors, 1);
477 goto buf_rel;
478 }
479
480 code = icmp6h->code;
481
482 /* メッセージの型により分岐する。*/
483 switch (icmp6h->type) {
484
485 case ICMP6_DST_UNREACH: /* 宛先到達不可能 */
486 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInDestUnreachs, 1);
487 icmp6_notify_error(input, off);
488 break;
489
490 case ICMP6_ECHO_REQUEST: /* エコー要求 */
491 icmp6_echo_request(input, off);
492 return IPPROTO_DONE;
493 break;
494
495 case ICMP6_ECHO_REPLY: /* エコー応答 */
496
497#ifdef ICMP_CFG_CALLBACK_ECHO_REPLY
498
499 icmp6_echo_reply(input, off);
500
501#endif /* of #ifdef ICMP_CFG_CALLBACK_ECHO_REPLY */
502
503 break;
504
505 case ND_ROUTER_ADVERT: /* ルータ通知 */
506 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInRouterAdvertisements, 1);
507 if (code != 0 || len < ROUTER_ADVERT_HDR_SIZE)
508 goto buf_rel;
509 nd6_ra_input(input, off);
510 return IPPROTO_DONE;
511 break;
512
513 case ND_NEIGHBOR_SOLICIT: /* 近隣要請 */
514 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInNeighborSolicits, 1);
515 if (code != 0 || len < NEIGHBOR_SOLICIT_HDR_SIZE)
516 goto buf_rel;
517 nd6_ns_input(input, off);
518 return IPPROTO_DONE;
519 break;
520
521 case ND_NEIGHBOR_ADVERT: /* 近隣通知 */
522 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInNeighborAdvertisements, 1);
523 if (code != 0 || len < NEIGHBOR_ADVERT_HDR_SIZE)
524 goto buf_rel;
525 nd6_na_input(input, off);
526 return IPPROTO_DONE;
527 break;
528
529 case ND_REDIRECT: /* 向け直し */
530 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInRedirects, 1);
531
532#if NUM_REDIRECT_ROUTE_ENTRY > 0
533
534 if (code != 0 || len < ND_REDIRECT_HDR_SIZE)
535 goto buf_rel;
536 icmp6_redirect_input(input, off);
537 return IPPROTO_DONE;
538
539#else /* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */
540
541 syslog(LOG_WARNING, "[ICMP6] redirect ignored.");
542
543#endif /* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */
544
545 break;
546
547 case ICMP6_PACKET_TOO_BIG: /* パケットが大きすぎる。 */
548
549#if NUM_IN6_HOSTCACHE_ENTRY > 0
550
551 icmp6_mtudisc_update(input, off, ntohl(icmp6h->icmp6_mtu));
552
553#endif /* of #if NUM_IN6_HOSTCACHE_ENTRY > 0 */
554
555 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInPktTooBigs, 1);
556 break;
557
558 case ICMP6_TIME_EXCEEDED: /* TTL を超過した。 */
559 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInTimeExcds, 1);
560 break;
561
562 case ICMP6_PARAM_PROB: /* IPv6 ヘッダが不正。 */
563 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInParmProblems, 1);
564 break;
565
566 case MLD_LISTENER_QUERY: /* マルチキャスト受信者照会 */
567 case MLD_LISTENER_REPORT: /* マルチキャスト受信者報告 */
568 case MLD_LISTENER_DONE: /* マルチキャスト受信者終了 */
569 case ND_ROUTER_SOLICIT: /* ルータ要請 */
570 case ICMP6_ROUTER_RENUMBERING: /* ルータ番号再設定 */
571 case ICMP6_FQDN_QUERY: /* FQDN 照会 */
572 case ICMP6_FQDN_REPLY: /* FQDN 応答 */
573 syslog(LOG_WARNING, "[ICMP6] unsupported type: %d.", icmp6h->type);
574 break;
575
576 default:
577 syslog(LOG_WARNING, "[ICMP6] unknown type: %d.", icmp6h->type);
578 NET_COUNT_ICMP6(net_count_icmp6[NC_ICMP6_IN_ERR_PACKETS], 1);
579 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpInErrors, 1);
580 break;
581 }
582
583buf_rel:
584 syscall(rel_net_buf(input));
585 return IPPROTO_DONE;
586 }
587
588/*
589 * icmp6_error -- ICMP6 エラー送信関数
590 */
591
592void
593icmp6_error (T_NET_BUF *input, uint8_t type, uint8_t code, uint32_t param)
594{
595 T_NET_BUF *output;
596 T_IP6_HDR *ip6h;
597 T_ICMP6_HDR *icmp6h;
598 ER_UINT off;
599 uint_t next, len;
600
601 ip6h = GET_IP6_HDR(input);
602
603 /*
604 * 宛先アドレスが、マルチキャストの場合は、
605 * 以下の条件以外のときは処理を行わない。
606 *
607 * ・データグラムが大きすぎる。
608 * ・IPv6 ヘッダの不正で、オプションが認識できない。
609 */
610 if (IN6_IS_ADDR_MULTICAST(&ip6h->dst) &&
611 !((type == ICMP6_PACKET_TOO_BIG) ||
612 (type == ICMP6_PARAM_PROB && code == ICMP6_PARAMPROB_OPTION)))
613 goto buf_rel;
614
615 /*
616 * 始点アドレスが、以下の場合は処理を行わない。
617 *
618 * ・無指定
619 * ・マルチキャスト
620 */
621 if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->src) ||
622 IN6_IS_ADDR_MULTICAST (&ip6h->src))
623 goto buf_rel;
624
625 /* 最後のヘッダを探索する。*/
626 off = ip6_lasthdr(input, 0, IPPROTO_IPV6, &next);
627
628 /*
629 * タイプが、エラーか向け直しの ICMP6 パケットのエラーには返答しない。
630 */
631 if (off >= 0 && next == IPPROTO_ICMPV6) {
632 T_ICMP6_HDR *icmp6h;
633
634 if (input->len - off < ICMP6_HDR_SIZE)
635 goto buf_rel;
636
637 icmp6h = GET_ICMP6_HDR(input, off);
638 if (icmp6h->type < ICMP6_ECHO_REQUEST ||
639 icmp6h->type == ND_REDIRECT)
640 goto buf_rel;
641 }
642
643 /* DoS 攻撃に対する防御は未実装 */
644
645 /*
646 * 送り返すメッセージ長を、ICMPv6 の最大ペイロード長に調整する。
647 * IPV6_MMTU - (IP6_HDR_SIZE + ICMP6_HDR_SIZE)
648 */
649 if (input->len - IF_HDR_SIZE > IPV6_MMTU - (IP6_HDR_SIZE + ICMP6_HDR_SIZE))
650 len = IPV6_MMTU - (IP6_HDR_SIZE + ICMP6_HDR_SIZE);
651 else
652 len = input->len - IF_HDR_SIZE;
653
654 /* 送信用のネットワークバッファを獲得する。*/
655 if (in6_get_datagram(&output, len + ICMP6_HDR_SIZE, 0,
656 &ip6h->src, &in6_addr_unspecified,
657 IPPROTO_ICMPV6, IPV6_MAXHLIM,
658 NBA_SEARCH_ASCENT, TMO_ICMP_OUTPUT) != E_OK)
659 goto buf_rel;
660
661 /* ICMP6 ヘッダを設定する。*/
662 icmp6h = GET_ICMP6_HDR(output, IF_IP6_ICMP6_HDR_OFFSET);
663 icmp6h->type = type;
664 icmp6h->code = code;
665 icmp6h->icmp6_pptr = htonl(param);
666
667 /* エラーデータを設定する。*/
668 memcpy(GET_ICMP6_SDU(output, IF_IP6_ICMP6_HDR_OFFSET), (uint8_t *)ip6h, len);
669
670#ifdef SUPPORT_MIB
671
672 switch (type) {
673 case ICMP6_DST_UNREACH:
674 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutDestUnreachs, 1);
675 break;
676
677 case ICMP6_PARAM_PROB:
678 NET_COUNT_MIB(icmp6_ifstat.ipv6IfIcmpOutParmProblems, 1);
679 break;
680
681 default:
682 break;
683
684 }
685
686#endif /* of #ifdef SUPPORT_MIB */
687
688 /* 送信する。*/
689 icmp6_output(output, IF_IP6_HDR_SIZE);
690
691buf_rel:
692 syscall(rel_net_buf(input));
693 }
694
695#endif /* of #ifdef SUPPORT_INET6 */
Note: See TracBrowser for help on using the repository browser.