source: azure_iot_hub/trunk/asp3_dcre/tinet/netinet/ip_icmp.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: 14.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/*
35 * Copyright (c) 1982, 1986, 1988, 1993
36 * The Regents of the University of California. All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
67 * $FreeBSD: src/sys/netinet/ip_icmp.c,v 1.33.2.3 1999/10/14 11:49:38 des Exp $
68 */
69
70#include <string.h>
71
72#ifdef TARGET_KERNEL_ASP
73
74#include <kernel.h>
75#include <sil.h>
76#include <t_syslog.h>
77#include "kernel_cfg.h"
78#include "tinet_cfg.h"
79
80#endif /* of #ifdef TARGET_KERNEL_ASP */
81
82#ifdef TARGET_KERNEL_JSP
83
84#include <s_services.h>
85#include <t_services.h>
86#include "tinet_id.h"
87
88#endif /* of #ifdef TARGET_KERNEL_JSP */
89
90#include <tinet_defs.h>
91#include <tinet_config.h>
92
93#include <net/if.h>
94#include <net/if_loop.h>
95#include <net/if_ppp.h>
96#include <net/ethernet.h>
97#include <net/ppp_ipcp.h>
98#include <net/net.h>
99#include <net/net_endian.h>
100#include <net/net_buf.h>
101#include <net/net_timer.h>
102#include <net/net_count.h>
103
104#include <netinet/in.h>
105#include <netinet/in_var.h>
106#include <netinet/ip.h>
107#include <netinet/ip_var.h>
108#include <netinet/ip_icmp.h>
109#include <netinet/icmp_var.h>
110#include <netinet/tcp.h>
111#include <netinet/tcp_var.h>
112#include <netinet/udp_var.h>
113
114#include <net/if_var.h>
115
116#if defined(_IP4_CFG)
117
118/*
119 * 変数
120 */
121
122#ifdef SUPPORT_MIB
123
124/*
125 * SNMP の 管理情報ベース (MIB)
126 */
127
128T_ICMP_STATS icmp_stats;
129
130#endif /* of #ifdef SUPPORT_MIB */
131
132/*
133 * 関数
134 */
135
136static void icmp_echo (T_NET_BUF *input, uint_t ihoff);
137static void icmp_unreach (T_NET_BUF *input, uint_t ihoff);
138
139#if defined(NUM_REDIRECT_ROUTE_ENTRY)
140#if NUM_REDIRECT_ROUTE_ENTRY > 0
141
142static void icmp_redirect (T_NET_BUF *input, uint_t ihoff);
143
144#endif /* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */
145#endif /* of #if defined(NUM_REDIRECT_ROUTE_ENTRY) */
146
147/*
148 * icmp_echo -- エコー要求を受信したときの処理
149 *
150 * input には IF ヘッダと IP ヘッダも含まれている。
151 */
152
153static void
154icmp_echo (T_NET_BUF *input, uint_t ihoff)
155{
156 T_IP4_HDR *ip4h;
157 T_ICMP4_HDR *icmp4h;
158 T_IFNET *ifp = IF_GET_IFNET();
159
160 NET_COUNT_MIB(icmp_stats.icmpInEchos, 1);
161
162 /* IPv4 アドレスが未定義の時は応答しない。*/
163 if (!IN4_IS_ADDR_ANY(&ifp->in4_ifaddr.addr)) {
164
165 /*
166 * メッセージの型をエコー要求 (8) から
167 * エコー応答 (0) に変更して送り返す。
168 */
169
170 icmp4h = GET_ICMP4_HDR(input, ihoff);
171 icmp4h->type = ICMP4_ECHO_REPLY;
172
173 /*
174 * 宛先アドレスは受信したメッセージの送信元アドレス。
175 * 送信元アドレスは自 IPv4 アドレス。
176 */
177 ip4h = GET_IP4_HDR(input);
178 ip4h->dst = ip4h->src;
179 ip4h->src = htonl(ifp->in4_ifaddr.addr);
180
181 /* チェックサムを計算する。*/
182 icmp4h->sum = 0;
183 icmp4h->sum = in_cksum(icmp4h,
184 (uint_t)(((input->len - GET_IF_IP4_HDR_SIZE(input)) + 3) >> 2 << 2));
185
186 /* 送信する。*/
187 NET_COUNT_ICMP4(net_count_icmp4.out_octets,
188 input->len - GET_IF_IP4_HDR_SIZE(input));
189 NET_COUNT_ICMP4(net_count_icmp4.out_packets, 1);
190 NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1);
191 NET_COUNT_MIB(icmp_stats.icmpOutEchoReps, 1);
192 ip_output(input, TMO_ICMP_OUTPUT);
193 }
194 }
195
196/*
197 * icmp_unreach -- ICMP4_UNREACH を受信したときの処理
198 */
199
200static const int8_t code2error[] = {
201 EV_HURCH, /* ICMP4_UNREACH_NET 0 */
202 EV_HURCH, /* ICMP4_UNREACH_HOST 1 */
203 EV_CNNRF, /* ICMP4_UNREACH_PROTOCOL 2 */
204 EV_CNNRF, /* ICMP4_UNREACH_PORT 3 */
205 EV_MSIZE, /* ICMP4_UNREACH_FLAG 4 */
206 EV_HURCH, /* ICMP4_UNREACH_SRC_FAIL 5 */
207 EV_HURCH, /* ICMP4_UNREACH_NET_UNKNOWN 6 */
208 EV_HURCH, /* ICMP4_UNREACH_HOST_UNKNOWN 7 */
209 EV_HURCH, /* ICMP4_UNREACH_ISOLATED 8 */
210 EV_HURCH, /* ICMP4_UNREACH_NET_PROHIB 9 */
211 EV_HURCH, /* ICMP4_UNREACH_HOST_PROHIB 10 */
212 EV_HURCH, /* ICMP4_UNREACH_TOS_NET 11 */
213 EV_HURCH, /* ICMP4_UNREACH_TOS_HOST 12 */
214 EV_HURCH, /* ICMP4_UNREACH_FILTER_PROHIB 13 */
215 EV_HURCH, /* ICMP4_UNREACH_HOST_PRECEDENCE 14 */
216 EV_HURCH, /* ICMP4_UNREACH_PRECEDENCE_CUTOFF 15 */
217 };
218
219static void
220icmp_unreach (T_NET_BUF *input, uint_t ihoff)
221{
222 T_IP4_HDR *ip4h;
223 uint8_t code;
224 ER error;
225
226 NET_COUNT_MIB(icmp_stats.icmpInDestUnreachs, 1);
227
228 ip4h = (T_IP4_HDR*)GET_ICMP4_SDU(input, ihoff);
229 code = GET_ICMP4_HDR(input, ihoff)->code;
230 error = code2error[code];
231
232 /* 最終ヘッダが TCP/UDP のみ対応する。*/
233 if (ip4h->proto == IPPROTO_TCP || ip4h->proto == IPPROTO_UDP) {
234
235 memcpy(GET_IP4_HDR(input), ip4h, input->len - (IP4_HDR_SIZE + ICMP4_HDR_SIZE));
236 input->len -= IP4_HDR_SIZE + ICMP4_HDR_SIZE;
237
238#if defined(SUPPORT_TCP)
239
240 if (ip4h->proto == IPPROTO_TCP)
241 tcp_notify(input, error);
242
243#endif /* of #if defined(SUPPORT_TCP) */
244
245#if defined(SUPPORT_UDP) && TNUM_UDP4_CEPID > 0
246
247 if (ip4h->proto == IPPROTO_UDP)
248 udp4_notify(input, error);
249
250#endif /* of #if defined(SUPPORT_UDP) && TNUM_UDP4_CEPID > 0 */
251
252 }
253 else
254 syslog(LOG_NOTICE, "[ICMP] error, code: %d.", code);
255 }
256
257#if defined(NUM_REDIRECT_ROUTE_ENTRY)
258#if NUM_REDIRECT_ROUTE_ENTRY > 0
259
260/*
261 * icmp_redirect -- 向け直しメッセージを受信したときの処理
262 *
263 * input には IF ヘッダと IP ヘッダも含まれている。
264 */
265
266static void
267icmp_redirect (T_NET_BUF *input, uint_t ihoff)
268{
269 T_IP4_HDR *ip4h, *sip4h;
270 T_ICMP4_HDR *icmp4h;
271
272 ip4h = GET_IP4_HDR(input);
273 icmp4h = GET_ICMP4_HDR(input, ihoff);
274 sip4h = (T_IP4_HDR *)GET_ICMP4_SDU(input, ihoff);
275
276 /*
277 * 内容チェック、以下の場合はエラー
278 *
279 * ・ICMP コードが、ICMP4_REDIRECT_PORT_AND_HOST (3) 以上
280 * ・データグラム長が、ICMP の最小長より短い (IP ヘッダ + ICMP ヘッダ + IP ヘッダ + 8)
281 * ・データグラム長が、ICMP の最大長より短い
282 * ・
283 */
284 if (icmp4h->code > ICMP4_REDIRECT_PORT_AND_HOST ||
285 ip4h->len < GET_IP4_ICMP4_HDR_SIZE(input) + 8 + IP4_HDR_SIZE ||
286 ip4h->len < GET_IP4_ICMP4_HDR_SIZE(input) + 8 + (IP4_VHL_HL(sip4h->vhl) << 2)) {
287 NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
288 return;
289 }
290
291 in4_rtredirect(icmp4h->data.addr, sip4h->dst, IN_RTF_REDIRECT, TMO_IN_REDIRECT);
292 }
293
294#endif /* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */
295#endif /* of #if defined(NUM_REDIRECT_ROUTE_ENTRY) */
296
297/*
298 * icmp_input -- ICMP の入力関数
299 *
300 * input には IF ヘッダと IP ヘッダも含まれている。
301 */
302
303uint_t
304icmp_input (T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
305{
306 T_NET_BUF *input = *inputp;
307 T_ICMP4_HDR *icmp4h;
308 T_IN4_ADDR addr;
309 uint_t len, align;
310
311 NET_COUNT_ICMP4(net_count_icmp4.in_octets,
312 input->len - GET_IF_IP4_HDR_SIZE(input));
313 NET_COUNT_ICMP4(net_count_icmp4.in_packets, 1);
314
315 /* ICMP ヘッダの長さをチェックする。*/
316 if (input->len < IF_IP4_ICMP4_HDR_SIZE) {
317 NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
318 NET_COUNT_MIB(icmp_stats.icmpInErrors, 1);
319 goto buf_rel;
320 }
321
322 icmp4h = (T_ICMP4_HDR *)(input->buf + *offp);
323
324 /* 4 オクテット境界のデータ長 */
325 len = input->len - *offp;
326 align = (len + 3) >> 2 << 2;
327
328 /* 4 オクテット境界までパディングで埋める。*/
329 if (align > len)
330 memset((uint8_t*)input->buf + input->len, 0, (size_t)(align - len));
331
332 /* チェックサムを計算する。*/
333 if (in_cksum(icmp4h, align) != 0) {
334 NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
335 goto buf_rel;
336 }
337
338 /* メッセージの型により分岐する。*/
339 switch (icmp4h->type) {
340 case ICMP4_ECHO_REQUEST:
341 icmp_echo(input, *offp);
342 return IPPROTO_DONE;
343 break;
344 case ICMP4_ECHO_REPLY:
345
346#if defined(SUPPORT_INET4) && defined(ICMP_CFG_CALLBACK_ECHO_REPLY)
347
348 icmp_echo_reply(input, *offp);
349
350#endif /* of #if defined(SUPPORT_INET4) && defined(ICMP_CFG_CALLBACK_ECHO_REPLY) */
351
352 break;
353 case ICMP4_UNREACH:
354 icmp_unreach(input, *offp);
355 break;
356 case ICMP4_REDIRECT:
357
358#if defined(NUM_REDIRECT_ROUTE_ENTRY)
359#if NUM_REDIRECT_ROUTE_ENTRY > 0
360
361 addr = ntohl(icmp4h->data.addr);
362 syslog(LOG_INFO, "[ICMP] redirect, addr: %s.", ip2str(NULL, &addr));
363 icmp_redirect(input, *offp);
364
365#else /* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */
366
367 addr = ntohl(icmp4h->data.addr);
368 syslog(LOG_INFO, "[ICMP] redirect ignored, addr: %s.", ip2str(NULL, &addr));
369
370#endif /* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */
371#else /* of #if defined(NUM_REDIRECT_ROUTE_ENTRY) */
372
373 addr = ntohl(icmp4h->data.addr);
374 syslog(LOG_INFO, "[ICMP] redirect ignored, addr: %s.", ip2str(NULL, &addr));
375
376#endif /* of #if defined(NUM_REDIRECT_ROUTE_ENTRY) */
377
378 break;
379 default:
380 syslog(LOG_INFO, "[ICMP] unknown type: %d.", icmp4h->type);
381 NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
382 break;
383 }
384
385buf_rel:
386 syscall(rel_net_buf(input));
387 return IPPROTO_DONE;
388 }
389
390#ifdef ICMP_REPLY_ERROR
391
392/*
393 * icmp_error -- ICMP エラー送信関数。
394 *
395 * input には IF ヘッダと IP ヘッダも含まれている。
396 * icmp_error では、ネットワークバッファ input を返却しないので、
397 * 呼出し側で、開放してから終了する。
398 */
399
400void
401icmp_error (uint8_t code, T_NET_BUF *input)
402{
403 T_IP4_HDR *ip4h;
404 T_ICMP4_HDR *icmp4h;
405 T_NET_BUF *output;
406 T_IN4_ADDR saddr;
407 uint_t len, ip4hl, align;
408
409 ip4h = GET_IP4_HDR(input);
410 ip4hl = GET_IP4_HDR_SIZE(input);
411
412 /* 送信用の IP データグラムを獲得する。*/
413 if (input->len - ip4hl < 8)
414 len = input->len - ip4hl;
415 else
416 len = 8;
417
418 saddr = ntohl(ip4h->src);
419 if (in4_get_datagram(&output, (uint_t)(ICMP4_HDR_SIZE + ip4hl + len), 0,
420 &saddr, NULL, IPPROTO_ICMP, IP4_DEFTTL,
421 NBA_SEARCH_ASCENT, TMO_ICMP_OUTPUT) != E_OK)
422 return;
423
424 /* ICMP ヘッダを設定する。*/
425 icmp4h = GET_ICMP4_HDR(output, IF_IP4_ICMP4_HDR_OFFSET);
426 icmp4h->type = ICMP4_UNREACH;
427 icmp4h->code = code;
428 icmp4h->data.addr= 0;
429
430 /* エラーが発生した IP ヘッダと データ 8 オクテットをコピーする。*/
431 memcpy(GET_ICMP4_SDU(output, IF_IP4_ICMP4_HDR_OFFSET),
432 GET_IP4_HDR(input), (size_t)(ip4hl + len));
433
434 /* 4 オクテット境界のデータ長 */
435 align = (len + 3) >> 2 << 2;
436
437 /* 4 オクテット境界までパディングで埋める。*/
438 if (align > len)
439 memset((uint8_t*)GET_ICMP4_SDU(output, IF_IP4_ICMP4_HDR_OFFSET) + ip4hl + len,
440 0, (size_t)(align - len));
441
442 /* チェックサムを計算する。*/
443 icmp4h->sum = 0;
444 icmp4h->sum = in_cksum(icmp4h, (uint_t)(ICMP4_HDR_SIZE + ip4hl + align));
445
446 /* 送信する。*/
447 NET_COUNT_ICMP4(net_count_icmp4.out_octets,
448 output->len - GET_IF_IP4_HDR_SIZE(output));
449 NET_COUNT_ICMP4(net_count_icmp4.out_packets, 1);
450 NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1);
451 NET_COUNT_MIB(icmp_stats.icmpOutDestUnreachs, 1);
452 ip_output(output, TMO_ICMP_OUTPUT);
453 }
454
455#endif /* of #ifdef ICMP_REPLY_ERROR */
456
457#endif /* of #if defined(_IP4_CFG) */
Note: See TracBrowser for help on using the repository browser.