source: asp3_tinet_ecnl_rx/trunk/asp3_dcre/tinet/netinet6/frag6.c@ 337

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

ASP3版ECNLを追加

  • 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-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/frag6.c,v 1.9 2002/04/19 04:46:22 suz Exp $ */
35/* $KAME: frag6.c,v 1.33 2002/01/07 11:34:48 kjc 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#include <string.h>
67
68#ifdef TARGET_KERNEL_ASP
69
70#include <kernel.h>
71#include <sil.h>
72#include "kernel_cfg.h"
73
74#endif /* of #ifdef TARGET_KERNEL_ASP */
75
76#ifdef TARGET_KERNEL_JSP
77
78#include <s_services.h>
79#include <t_services.h>
80#include "kernel_id.h"
81
82#endif /* of #ifdef TARGET_KERNEL_JSP */
83
84#include <tinet_defs.h>
85#include <tinet_config.h>
86
87#include <net/if.h>
88#include <net/if_loop.h>
89#include <net/if_ppp.h>
90#include <net/ethernet.h>
91#include <net/if_arp.h>
92#include <net/ppp_ipcp.h>
93#include <net/net.h>
94#include <net/net_endian.h>
95#include <net/net_buf.h>
96#include <net/net_var.h>
97#include <net/net_count.h>
98
99#include <netinet/in.h>
100#include <netinet/in_var.h>
101#include <netinet/ip.h>
102#include <netinet/ip_var.h>
103#include <netinet/ip_icmp.h>
104#include <netinet6/nd6.h>
105
106#ifdef _IP6_CFG
107
108#ifdef IP6_CFG_FRAGMENT
109
110/*
111 * データグラム再構成キュー配列
112 */
113
114static T_NET_BUF *ip6_frag_queue[NUM_IP6_FRAG_QUEUE];
115static T_IN6_ADDR ip6_frag_dest [NUM_IP6_FRAG_QUEUE];
116
117/*
118 * ip6_get_frag_queue -- データグラム再構成キューを獲得する。
119 */
120
121const T_NET_BUF **
122ip6_get_frag_queue (void)
123{
124 return (const T_NET_BUF **)ip6_frag_queue;
125 }
126
127/*
128 * frag6_free_queue -- データグラム再構成キューを解放する。
129 *
130 * 注意: データグラム再構成キュー配列をロックしてから呼び出すこと。
131 */
132
133static void
134frag6_free_queue (T_NET_BUF **queue)
135{
136 T_NET_BUF *frag, *next;
137 T_QIP6_HDR *qip6h;
138
139 frag = *queue;
140 while (frag != NULL) {
141 qip6h = GET_QIP6_HDR(frag);
142 next = qip6h->next_frag;
143 syscall(rel_net_buf(frag));
144 frag = next;
145 }
146 *queue = NULL;
147 }
148
149/*
150 * frag6_timer -- データグラム再構成管理タイマ
151 */
152
153void
154frag6_timer (void)
155{
156 T_NET_BUF *frag;
157 T_QIP6_HDR *qip6h;
158 T_IP6_FRAG_HDR *qip6fh;
159 int_t ix;
160
161 syscall(wai_sem(SEM_IP6_FRAG_QUEUE));
162 for (ix = NUM_IP6_FRAG_QUEUE; ix -- > 0; ) {
163 frag = ip6_frag_queue[ix];
164 if (frag != NULL) {
165 qip6h = GET_QIP6_HDR(frag);
166 if (qip6h->ftim > 0 && -- qip6h->ftim == 0) {
167
168 qip6fh = (T_IP6_FRAG_HDR *)(frag->buf + qip6h->foff);
169 if (ntohs(qip6fh->off_flag & IP6F_OFF_MASK) == 0) {
170
171 /*
172 * 先頭の断片のオフセットが 0 の時のみ
173 * ICMPv6 エラーメッセージを送信する。
174 */
175
176 /* 先頭の断片をデータグラム再構成キューから外す。*/
177 ip6_frag_queue[ix] = qip6h->next_frag;
178
179 /* あて先アドレスを元に戻す。*/
180 GET_IP6_HDR(frag)->dst = ip6_frag_dest[ix];
181
182 /* ICMPv6 エラーメッセージを送信する。*/
183 icmp6_error(frag, ICMP6_TIME_EXCEEDED,
184 ICMP6_TIME_EXCEED_REASSEMBLY, 0);
185 }
186
187 /* データグラム再構成キューを解放する。*/
188 NET_COUNT_IP6(net_count_ip6[NC_IP6_FRAG_IN_TMOUT], 1);
189 NET_COUNT_IP6(net_count_ip6[NC_IP6_FRAG_IN_DROP], 1);
190 frag6_free_queue(&ip6_frag_queue[ix]);
191 }
192 }
193 }
194 syscall(sig_sem(SEM_IP6_FRAG_QUEUE));
195 }
196
197#endif /* #ifdef IP6_CFG_FRAGMENT */
198
199/*
200 * frag6_input -- 断片ヘッダの入力関数
201 */
202
203uint_t
204frag6_input (T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
205{
206 T_IP6_HDR *ip6h;
207 T_IP6_FRAG_HDR *ip6fh;
208 T_NET_BUF *input = *inputp;
209 uint_t off = *offp;
210
211#ifdef IP6_CFG_FRAGMENT
212
213 T_QIP6_HDR *qip6h, *rip6h;
214 T_IP6_FRAG_HDR *qip6fh = NULL;
215 T_NET_BUF **ip6fq = NULL, *prev, *next, *frag;
216 int_t ix;
217 int32_t unfraglen, diff;
218 uint16_t fragpartlen, qfragpartlen, fragoff, qfragoff, plen;
219 uint8_t ftim, *prev_next;
220 uint_t nextproto = IPPROTO_DONE;
221
222#endif /* #ifdef IP6_CFG_FRAGMENT */
223
224 /* ネットワークバッファの残りの長さをチェックする。*/
225 if (input->len - off < sizeof(T_IP6_FRAG_HDR))
226 goto buf_rel;
227
228 /*
229 * 巨大ペイロードオプションと断片ヘッダを同時に使用することは
230 * できない。ペイロード長がが 0 なら、巨大ペイロードオプションが
231 * 指定されていることになるので ICMP でエラーを送信者に
232 * 通知する。
233 */
234 ip6h = GET_IP6_HDR(input);
235 if (ip6h->plen == 0) {
236 icmp6_error(input, ICMP6_PARAM_PROB,
237 ICMP6_PARAMPROB_HEADER,
238 off - IF_HDR_SIZE);
239 NET_COUNT_MIB(in6_stats.ipv6IfStatsReasmFails, 1);
240 return IPPROTO_DONE;
241 }
242
243 /*
244 * オフセットが 0 で、最終フラグメントであれば、
245 * 分割不要のデータグラムなので、
246 * 次ヘッダを指す変数を調整して終了する。
247 */
248 ip6fh = (T_IP6_FRAG_HDR *)(input->buf + off);
249 if (ip6fh->off_flag == 0) {
250 *nextp = *offp - IF_HDR_SIZE + offsetof(T_IP6_FRAG_HDR, next);
251 *offp = off + sizeof(T_IP6_FRAG_HDR);
252 return ip6fh->next;
253 }
254
255#ifdef IP6_CFG_FRAGMENT
256
257 /*
258 * ペイロード長をチェックする。
259 */
260 if ((ip6fh->off_flag & IP6F_MORE_FRAG) &&
261 ((ntohs(ip6h->plen) - (off - IF_HDR_SIZE)) & 0x7) != 0) {
262 icmp6_error(input, ICMP6_PARAM_PROB,
263 ICMP6_PARAMPROB_HEADER,
264 offsetof(T_IP6_HDR, plen));
265 NET_COUNT_MIB(in6_stats.ipv6IfStatsReasmFails, 1);
266 return nextproto;
267 }
268 NET_COUNT_MIB(in6_stats.ipv6IfStatsReasmReqds, 1);
269
270 syscall(wai_sem(SEM_IP6_FRAG_QUEUE));
271
272 /*
273 * データグラム再構成キュー配列から、対応するエントリを探す。
274 */
275 for (ix = NUM_IP6_FRAG_QUEUE; ix -- > 0; ) {
276 if (ip6_frag_queue[ix] != NULL) {
277 qip6h = GET_QIP6_HDR(ip6_frag_queue[ix]);
278 qip6fh = (T_IP6_FRAG_HDR *)(ip6_frag_queue[ix]->buf + qip6h->foff);
279 if (ip6fh->ident == qip6fh->ident &&
280 IN6_ARE_ADDR_EQUAL(&ip6h->src, &qip6h->src) &&
281 IN6_ARE_ADDR_EQUAL(&ip6h->dst, &ip6_frag_dest[ix])) {
282 ip6fq = &ip6_frag_queue[ix];
283 break;
284 }
285 }
286 }
287
288 if (ip6fq == NULL) {
289
290 /*
291 * 断片の正当性をチェックする。
292 */
293 unfraglen = 0;
294 fragoff = ntohs(ip6fh->off_flag & IP6F_OFF_MASK);
295 if (fragoff == 0) {
296
297 /*
298 * 入力した断片が先頭の断片
299 * 分割できない部分の長さ unfraglen を計算する。
300 */
301 unfraglen = (off - IF_HDR_SIZE) - sizeof(T_IP6_HDR);
302 }
303
304 /*
305 * off
306 * |<--------------------------->|
307 * | off - IF_HDR_SIZE |
308 * | |<------------------>|
309 * | | off - IF_HDR_SIZE + IP6_FRAG_HDR_SIZE |
310 * | |<------------------------------------->|
311 * +--------+----------+---------+------------------+-------------+
312 * | IF HDR | IPv6 HDR | EXT HDR | FRAG HDR | Payload |
313 * +--------+----------+---------+------------------+-------------+
314 * |<---------------------------------------->|
315 * | Payload Size |
316 * |<--------------------------------------------------->|
317 * | IP6_HDR_SIZE + Payload Size |
318 * |<----------->|
319 * | fragpartlen |
320 */
321 fragpartlen = sizeof(T_IP6_HDR) + ntohs(ip6h->plen) - (off - IF_HDR_SIZE + sizeof(T_IP6_FRAG_HDR));
322 if (unfraglen + fragoff + fragpartlen > IPV6_MAXPACKET) {
323 icmp6_error(input, ICMP6_PARAM_PROB,
324 ICMP6_PARAMPROB_HEADER,
325 (off - IF_HDR_SIZE) +
326 offsetof(T_IP6_FRAG_HDR, off_flag));
327 goto sig_ret;
328 }
329
330 /*
331 * ip6fq == NULL であれば、対応するエントリは無いので、
332 * データグラム再構成キュー配列に、エントリを追加する。
333 */
334 for (ix = NUM_IP6_FRAG_QUEUE; ix -- > 0; ) {
335
336 /* 空きエントリを探す。*/
337 if (ip6_frag_queue[ix] == NULL) {
338 ip6fq = &ip6_frag_queue[ix];
339 break;
340 }
341 }
342
343 /*
344 * ip6fq == NULL であれば、空きエントリが無いので、
345 * タイムアウト(hlim)が短いエントリを開放する。
346 */
347 if (ip6fq == NULL) {
348
349 ftim = IPV6_MAXHLIM;
350 for (ix = NUM_IP6_FRAG_QUEUE; ix -- > 0; ) {
351 if (ip6_frag_queue[ix] != NULL) {
352 rip6h = GET_QIP6_HDR(ip6_frag_queue[ix]);
353 if (rip6h->ftim < ftim) {
354 ftim = rip6h->ftim;
355 ip6fq = &ip6_frag_queue[ix];
356 }
357 }
358 }
359 frag6_free_queue(ip6fq);
360 }
361
362 /*
363 * エントリを設定する。
364 */
365 *ip6fq = input;
366 ip6_frag_dest[ip6fq - ip6_frag_queue] = ip6h->dst;
367 qip6h = GET_QIP6_HDR(*ip6fq);
368 qip6h->ftim = IPV6_FRAGTTL;
369 qip6h->foff = off;
370 qip6h->flen = fragpartlen;
371 qip6h->next_frag = NULL;
372 }
373 else {
374
375 /*
376 * 断片の正当性をチェックする。
377 */
378 unfraglen = 0;
379 fragoff = ntohs(((T_IP6_FRAG_HDR *)((*ip6fq)->buf + GET_QIP6_HDR(*ip6fq)->foff))->off_flag & IP6F_OFF_MASK);
380 if (fragoff == 0) {
381
382 /*
383 * データグラム再構成キューの最初の断片が先頭の断片
384 * 分割できない部分の長さ unfraglen を計算する。
385 */
386 unfraglen = (GET_QIP6_HDR(*ip6fq)->foff - IF_HDR_SIZE) - sizeof(T_IP6_HDR);
387 }
388
389 fragoff = ntohs(ip6fh->off_flag & IP6F_OFF_MASK);
390 if (fragoff == 0) {
391
392 /*
393 * 入力した断片が先頭の断片
394 * 分割できない部分の長さ unfraglen を計算する。
395 */
396 unfraglen = (off - IF_HDR_SIZE) - sizeof(T_IP6_HDR);
397 }
398
399 /*
400 * off
401 * |<--------------------------->|
402 * | off - IF_HDR_SIZE |
403 * | |<------------------>|
404 * | | off - IF_HDR_SIZE + IP6_FRAG_HDR_SIZE |
405 * | |<------------------------------------->|
406 * +--------+----------+---------+------------------+-------------+
407 * | IF HDR | IPv6 HDR | EXT HDR | FRAG HDR | Payload |
408 * +--------+----------+---------+------------------+-------------+
409 * |<---------------------------------------->|
410 * | Payload Size |
411 * |<--------------------------------------------------->|
412 * | IP6_HDR_SIZE + Payload Size |
413 * |<----------->|
414 * | fragpartlen |
415 */
416 fragpartlen = sizeof(T_IP6_HDR) + ntohs(ip6h->plen) - (off - IF_HDR_SIZE + sizeof(T_IP6_FRAG_HDR));
417 if (unfraglen + fragoff + fragpartlen > IPV6_MAXPACKET) {
418 icmp6_error(input, ICMP6_PARAM_PROB,
419 ICMP6_PARAMPROB_HEADER,
420 (off - IF_HDR_SIZE) +
421 offsetof(T_IP6_FRAG_HDR, off_flag));
422 goto sig_ret;
423 }
424
425 if (ntohs(ip6fh->off_flag & IP6F_OFF_MASK) == 0) {
426
427 /*
428 * 入力した断片が先頭の断片
429 * データグラム再構成キューの最後の断片が、
430 * データグラムの最大長を超えていないかチェックする。
431 */
432
433 /* 最後の断片を探索する。*/
434 next = *ip6fq;
435 while ((qip6h = GET_QIP6_HDR(next))->next_frag != NULL)
436 next = qip6h->next_frag;
437
438 /* 最後の断片のオフセットと断片サイズを計算する。*/
439 qip6fh = (T_IP6_FRAG_HDR *)(next->buf + qip6h->foff);
440 fragoff = ntohs(qip6fh->off_flag & IP6F_OFF_MASK);
441 fragpartlen = sizeof(T_IP6_HDR) + ntohs(qip6h->plen) - (qip6h->foff - IF_HDR_SIZE + sizeof(T_IP6_FRAG_HDR));
442 if (unfraglen + fragoff + fragpartlen > IPV6_MAXPACKET) {
443
444 /*
445 * データグラムの最大長を超えている場合は、
446 * データグラム再構成キュー全体を破棄する。
447 */
448 frag6_free_queue(ip6fq);
449 syscall(rel_net_buf(input));
450 goto sig_ret;
451 }
452 }
453
454 /* ECN の正当性チェックは未実装 */
455
456 /*
457 * 断片をエントリに挿入する。
458 * データグラム再構成キューから、入力した断片より前の断片を探索する。
459 */
460 prev = NULL;
461 next = *ip6fq;
462 while (next != NULL) {
463 qip6h = GET_QIP6_HDR(next);
464 qip6fh = (T_IP6_FRAG_HDR *)(next->buf + qip6h->foff);
465 if (ntohs(ip6fh->off_flag & IP6F_OFF_MASK) <= ntohs(qip6fh->off_flag & IP6F_OFF_MASK))
466 break;
467 prev = next;
468 next = qip6h->next_frag;
469 }
470
471 /*
472 * prev は、入力した断片より前の断片。ただし NULL の場合は、
473 * 入力した断片がデータグラム再構成キューの中で最も前の断片。
474 * next は、入力した断片より後の断片。ただし NULL の場合は、
475 * 入力した断片がデータグラム再構成キューの中で最も後の断片。
476 */
477 fragoff = ntohs(ip6fh->off_flag & IP6F_OFF_MASK);
478 if (prev != NULL) {
479
480 /*
481 * 前の断片と、入力した断片が重なっていないかチェックする。
482 *
483 * qfragoff
484 * | qfragparglen
485 * |<------------------>|
486 * +--------------------+
487 * | prev |
488 * +--------------------+
489 *
490 * +--------------------+
491 * | input |
492 * +--------------------+
493 * |
494 * fragoff
495 */
496 qip6h = GET_QIP6_HDR(prev);
497 qip6fh = (T_IP6_FRAG_HDR *)(prev->buf + qip6h->foff);
498 qfragoff = ntohs(qip6fh->off_flag & IP6F_OFF_MASK);
499 qfragpartlen = sizeof(T_IP6_HDR) + ntohs(qip6h->plen) - (off - IF_HDR_SIZE + sizeof(T_IP6_FRAG_HDR));
500
501 diff = ((int32_t)qfragoff + qfragpartlen) - fragoff;
502 if (diff > 0) {
503
504 /* 重なっていれば、入力した断片を破棄して終了する。*/
505 syscall(rel_net_buf(input));
506 goto sig_ret;
507 }
508 }
509
510 if (next != NULL) {
511
512 /*
513 * 後の断片と、入力した断片が重なっていないかチェックする。
514 *
515 * fragoff
516 * | fragparglen
517 * |<------------------>|
518 * +--------------------+
519 * | input |
520 * +--------------------+
521 *
522 * +--------------------+
523 * | next |
524 * +--------------------+
525 * |
526 * qfragoff
527 */
528 qip6h = GET_QIP6_HDR(next);
529 qip6fh = (T_IP6_FRAG_HDR *)(next->buf + qip6h->foff);
530 qfragoff = ntohs(qip6fh->off_flag & IP6F_OFF_MASK);
531 fragpartlen = sizeof(T_IP6_HDR) + ntohs(ip6h->plen) - (off - IF_HDR_SIZE + sizeof(T_IP6_FRAG_HDR));
532
533 diff = ((int32_t)fragoff + fragpartlen) - qfragoff;
534 if (diff > 0) {
535
536 /* 重なっていれば、入力した断片を破棄して終了する。*/
537 syscall(rel_net_buf(input));
538 goto sig_ret;
539 }
540 }
541
542 /* 入力した断片を設定する。*/
543 qip6h = GET_QIP6_HDR(input);
544 qip6h->foff = off;
545 qip6h->flen = sizeof(T_IP6_HDR) + ntohs(qip6h->plen) - (off - IF_HDR_SIZE + sizeof(T_IP6_FRAG_HDR));
546
547 if (prev == NULL) {
548 *ip6fq = input;
549 qip6h->ftim = IPV6_FRAGTTL;
550 }
551 else
552 GET_QIP6_HDR(prev)->next_frag = input;
553 qip6h->next_frag = next;
554
555 /*
556 * 全ての断片を受信したかチェックする。
557 */
558 plen = 0;
559 frag = *ip6fq;
560 while (frag != NULL) {
561 qip6h = GET_QIP6_HDR(frag);
562 qip6fh = (T_IP6_FRAG_HDR *)(frag->buf + qip6h->foff);
563 if (ntohs(qip6fh->off_flag & IP6F_OFF_MASK) != plen) {
564
565 /* 断片が連続していない。*/
566 goto sig_ret;
567 }
568 plen += qip6h->flen;
569 frag = qip6h->next_frag;
570 }
571 if (ntohs(qip6fh->off_flag & IP6F_MORE_FRAG) != 0) {
572
573 /* 最後の断片を受信していない。*/
574 goto sig_ret;
575 }
576
577 /*
578 * 全ての断片を受信したので、再構成する。
579 */
580
581 /* ネットワークバッファを獲得する。*/
582 qip6h = GET_QIP6_HDR(*ip6fq);
583 qip6fh = (T_IP6_FRAG_HDR *)((*ip6fq)->buf + qip6h->foff);
584 if (tget_net_buf(inputp, qip6h->foff + plen, TMO_IP6_FRAG_GET_NET_BUF) == E_OK) {
585
586 /*
587 * 断片ヘッダの直前のヘッダの NEXT フィールドのアドレスを獲得し、
588 * 元に戻す。
589 */
590 if ((prev_next = ip6_get_prev_hdr(*ip6fq, qip6h->foff)) == NULL) {
591 syscall(rel_net_buf(input));
592 goto sig_ret;
593 }
594 *prev_next = qip6fh->next;
595 input = *inputp;
596
597 NET_COUNT_IP6(net_count_ip6[NC_IP6_FRAG_IN_OK], 1);
598 NET_COUNT_MIB(in6_stats.ipv6IfStatsReasmOKs, 1);
599
600 /*
601 * IPv6 ヘッダと分割できない部分を
602 * データグラム再構成キューの中の先頭の断片からコピーする。
603 */
604 memcpy(input->buf, (*ip6fq)->buf, qip6h->foff);
605
606 /* 送信先アドレスを元に戻す。*/
607 ip6h = GET_IP6_HDR(input);
608 memcpy(&ip6h->dst, &ip6_frag_dest[ip6fq - ip6_frag_queue], sizeof(T_IN6_ADDR));
609
610 /* offp を、再構成した断片の先頭に設定する。*/
611 *offp = qip6h->foff;
612
613 /* ネットワークバッファ長を設定する。*/
614 input->len = plen + qip6h->foff;
615
616 /*
617 * 全ての断片をコピーする。
618 */
619 frag = *ip6fq;
620 off = qip6h->foff;
621 while (frag != NULL) {
622 qip6h = GET_QIP6_HDR(frag);
623 memcpy(input->buf + off,
624 frag->buf + qip6h->foff + sizeof(T_IP6_FRAG_HDR),
625 qip6h->flen);
626 off += qip6h->flen;
627 frag = qip6h->next_frag;
628 }
629
630 /* ペイロード長を設定する。*/
631 ip6h->plen = htons(plen);
632
633 *nextp = offsetof(T_IP6_HDR, next);
634 nextproto = ip6h->next;
635 }
636 else {
637 NET_COUNT_IP6(net_count_ip6[NC_IP6_FRAG_IN_NO_BUF], 1);
638 NET_COUNT_IP6(net_count_ip6[NC_IP6_FRAG_IN_DROP], 1);
639 NET_COUNT_MIB(in6_stats.ipv6IfStatsReasmFails, 1);
640 }
641
642 /* データグラム再構成キューを解放する。*/
643 frag6_free_queue(ip6fq);
644 }
645
646sig_ret:
647 syscall(sig_sem(SEM_IP6_FRAG_QUEUE));
648 return nextproto;
649
650#else /* #ifdef IP6_CFG_FRAGMENT */
651
652 /*
653 * データグラムの分割・再構成行わない場合は、全断片を破棄し、
654 * 最後の断片を受信したとき、
655 * ICMP エラーを送信者に通知する。
656 */
657 if ((ip6fh->off_flag & IP6F_MORE_FRAG) == 0) {
658 icmp6_error(input, ICMP6_TIME_EXCEEDED,
659 ICMP6_TIME_EXCEED_REASSEMBLY, 0);
660 NET_COUNT_MIB(in6_stats.ipv6IfStatsReasmFails, 1);
661 return IPPROTO_DONE;
662 }
663
664#endif /* #ifdef IP6_CFG_FRAGMENT */
665
666buf_rel:
667 syscall(rel_net_buf(input));
668 return IPPROTO_DONE;
669 }
670
671#endif /* of #ifdef _IP6_CFG */
Note: See TracBrowser for help on using the repository browser.