source: asp3_tinet_ecnl_rx/trunk/asp3_dcre/tinet/netinet/tcp_input.c@ 387

Last change on this file since 387 was 387, 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: 55.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 * 上記著作権者は,以下の (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, 1990, 1993, 1994, 1995
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 * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95
67 * $FreeBSD: src/sys/netinet/tcp_input.c,v 1.82.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
79#endif /* of #ifdef TARGET_KERNEL_ASP */
80
81#ifdef TARGET_KERNEL_JSP
82
83#include <s_services.h>
84#include <t_services.h>
85#include "kernel_id.h"
86
87#endif /* of #ifdef TARGET_KERNEL_JSP */
88
89#include <tinet_defs.h>
90#include <tinet_config.h>
91
92#include <net/if.h>
93#include <net/if_ppp.h>
94#include <net/if_loop.h>
95#include <net/ethernet.h>
96#include <net/net.h>
97#include <net/net_endian.h>
98#include <net/net_var.h>
99#include <net/net_buf.h>
100#include <net/net_timer.h>
101#include <net/net_count.h>
102
103#include <netinet/in.h>
104#include <netinet/in_var.h>
105#include <netinet/in_itron.h>
106#include <netinet/ip.h>
107#include <netinet/ip_var.h>
108#include <netinet/ip_icmp.h>
109#include <netinet/tcp.h>
110#include <netinet/tcp_var.h>
111#include <netinet/tcp_fsm.h>
112#include <netinet/tcp_seq.h>
113#include <netinet/tcp_timer.h>
114
115#ifdef SUPPORT_TCP
116
117/*
118 * 戻り値
119 *
120 * RET_OK 正常
121 * RET_DROP エラー、セグメントを破棄する。
122 * RET_RST_DROP エラー、RST を送信し、セグメントを破棄する。
123 */
124
125#define RET_OK (0)
126#define RET_NEED_OUTPUT (1)
127#define RET_RETURN (2)
128#define RET_DROP (-1)
129#define RET_RST_DROP (-2)
130
131/*
132 * 関数
133 */
134
135static void close_connection (T_TCP_CEP *cep, bool_t *needoutput);
136static void set_rexmt_timer (T_TCP_CEP *cep, T_TCP_TIME rtt);
137static uint8_t reassemble (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, uint8_t flags);
138static ER drop_after_ack (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff);
139static ER listening (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, T_TCP_SEQ iss);
140static ER proc_ack1 (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, bool_t *needoutput);
141static ER proc_ack2 (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, bool_t *needoutput);
142static ER syn_sent (T_TCP_HDR *tcph, T_TCP_CEP *cep);
143static void trim_length (T_TCP_HDR *tcph, T_TCP_CEP *cep);
144static void parse_option (T_TCP_HDR *tcph, T_TCP_CEP *cep);
145static bool_t update_wnd (T_TCP_HDR *tcph, T_TCP_CEP *cep);
146static void proc_urg (T_TCP_HDR *tcph, T_TCP_CEP *cep);
147
148/*
149 * parse_option -- TCP ヘッダのオプションを解析する。
150 */
151
152static void
153parse_option (T_TCP_HDR *tcph, T_TCP_CEP *cep)
154{
155 uint8_t *opt, type = 0;
156 uint_t len, ol, ssize;
157
158 opt = (uint8_t*)tcph + TCP_HDR_SIZE;
159 len = (uint_t)(TCP_HDR_LEN(tcph->doff) - TCP_HDR_SIZE);
160 while (len > 0 && (type = *opt) != TCP_OPT_EOL) {
161 if (type == TCP_OPT_NOP)
162 ol = 1u;
163 else {
164 if (len < 2)
165 break;
166 ol = *(opt + 1);
167 if (ol < 2 || ol > len)
168 break;
169 }
170 switch (type) {
171 case TCP_OPT_NOP:
172 break;
173 case TCP_OPT_MAXSEG:
174 if ((ol == TCP_OPT_LEN_MAXSEG) && (tcph->flags & TCP_FLG_SYN)) {
175 ssize = ntohs(*(uint16_t*)(opt + 2));
176 if (ssize > MAX_TCP_SND_SEG)
177 cep->maxseg = MAX_TCP_SND_SEG;
178 else if (ssize < TCP_MINMSS)
179 cep->maxseg = TCP_MINMSS;
180 else
181 cep->maxseg = ssize;
182 }
183 break;
184
185 case TCP_OPT_WINDOW:
186 case TCP_OPT_SACK_PERM:
187 case TCP_OPT_TIMESTAMP:
188 case TCP_OPT_CC:
189 case TCP_OPT_CCNEW:
190 case TCP_OPT_CCECHO:
191 syslog(LOG_INFO, "[TCP] unsup opt: %d.", type);
192 break;
193
194 default:
195 syslog(LOG_NOTICE, "[TCP] unexp opt: %d.", type);
196 break;
197 }
198 opt += ol;
199 len -= ol;
200 }
201 }
202
203/*
204 * set_rexmt_timer -- 新しい往復時間を収集し、再送タイマを更新する。
205 */
206
207static void
208set_rexmt_timer (T_TCP_CEP *cep, T_TCP_TIME rtt)
209{
210 T_TCP_TIME delta;
211
212 NET_COUNT_TCP(net_count_tcp[NC_TCP_RTT_UPDATES], 1);
213 if (cep->srtt != 0) {
214 /*
215 * srtt: 平滑化された RTT
216 *
217 * 計測された RTT (rtt) と現在の平滑化された RTT (srtt) の差 (delta) を求める。
218 *
219 * delta は 2 ビット左シフト ( 4 倍) した値で保持する。
220 * srtt は 5 ビット左シフト (32 倍) した値で保持されている。
221 *
222 * delta = rtt / 8 - srtt / 8
223 *
224 * 新しい srtt は
225 *
226 * srtt = rtt / 8 + srtt * 7 / 8
227 * = srtt + (rtt / 8 - srtt / 8)
228 *
229 * で計算する。
230 * このため、rtt を 2 ビット左シフトし、srtt を (5 - 2) ビット右シフトして delta を求める。
231 */
232 delta = ((rtt - 1) << TCP_DELTA_SHIFT) - (cep->srtt >> (TCP_SRTT_SHIFT - TCP_DELTA_SHIFT));
233 cep->srtt += delta;
234 if (cep->srtt <= 0)
235 cep->srtt = 1;
236
237 /*
238 * delta の絶対値 | delta | を求める。
239 */
240 if (delta < 0)
241 delta = - delta;
242
243 /*
244 * rttvar: 平滑化された分散
245 *
246 * rttvar は 4 ビット左シフト (16 倍) した値で保持されている。
247 *
248 * delta = |delta| / 4 - rttvar / 4
249 *
250 * 新しい rttvar は
251 *
252 * rttvar = |delta|/ 4 + rttvar * 3 /4
253 * = rttvar + (|delta| / 4 - rttvar / 4)
254 *
255 * で計算する。
256 */
257 delta -= cep->rttvar >> (TCP_RTTVAR_SHIFT - TCP_DELTA_SHIFT);
258 cep->rttvar += delta;
259 if (cep->rttvar <= 0)
260 cep->rttvar = 1;
261 }
262 else {
263 /*
264 * まだ srtt の設定が行われていないときは、今回計測された RTT を使用する。
265 * 平滑化された RTT (srtt) には、RTT を 5 ビット左シフト (32倍) した値。
266 * 平滑化された分散 (rttvar) には、RTT の 1/2 を 4 ビット左シフト (16倍) した値。
267 */
268 cep->srtt = rtt << TCP_SRTT_SHIFT;
269 cep->rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
270 }
271
272 /*
273 * rtt の測定を終了し、再送回数をリセットする。
274 */
275 cep->rtt = cep->rxtshift = 0;
276
277 /*
278 * RTT に許される最小値 と rtt + 2 の大きな値の方を再送タイムアウトの最小値にする。
279 */
280 if (rtt + 2 < TCP_TVAL_MIN)
281 cep->rxtcur = tcp_range_set(tcp_rexmt_val(cep),
282 (T_TCP_TIME)TCP_TVAL_MIN,
283 (T_TCP_TIME)TCP_TVAL_MAX_REXMT);
284 else
285 cep->rxtcur = tcp_range_set(tcp_rexmt_val(cep),
286 (T_TCP_TIME)(rtt + 2),
287 (T_TCP_TIME)TCP_TVAL_MAX_REXMT);
288 }
289
290/*
291 * reassemble -- 受信セグメントを再構成する。順番通りに受信したときの処理
292 */
293
294static uint8_t
295reassemble (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, uint8_t flags)
296{
297 T_TCP_Q_HDR *qhdr;
298 T_TCP_HDR *tcph;
299
300 tcph = GET_TCP_HDR(input, thoff);
301 if (tcph->sum > cep->rbufsz - cep->rwbuf_count) {
302 /*
303 * 受信ウィンドバッファに空きがないときは破棄する。
304 */
305 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_DROP_SEGS], 1);
306 syscall(rel_net_buf(input));
307 cep->flags |= TCP_CEP_FLG_ACK_NOW;
308 flags &= ~TCP_FLG_FIN;
309 }
310 else if (tcph->seq == cep->rcv_nxt &&
311 cep->reassq == NULL &&
312 cep->fsm_state == TCP_FSM_ESTABLISHED) {
313 /*
314 * 順番通りにセグメントを受信した時の処理
315 * 受信セグメントの並べ替えは不要なので
316 * そのまま受信ウィンドバッファに書き込む。
317 */
318
319#ifdef TCP_CFG_DELAY_ACK
320
321 cep->flags |= TCP_CEP_FLG_DEL_ACK;
322
323#else/* of #ifdef TCP_CFG_DELAY_ACK */
324
325 cep->flags |= TCP_CEP_FLG_ACK_NOW;
326
327#endif/* of #ifdef TCP_CFG_DELAY_ACK */
328
329 qhdr = GET_TCP_Q_HDR(input, thoff);
330
331 /* TCP ヘッダの位置を保存する。*/
332 SET_IP_TCP_Q_HDR_OFFSET(input, thoff);
333
334 /* SDU のオフセット(元はウィンドサイズ)をリセットする。*/
335 qhdr->soff = 0;
336
337 /* データを受信ウィンドバッファに書き込む。*/
338 TCP_WRITE_RWBUF(cep, input, thoff);
339 }
340 else {
341 flags = tcp_write_raque(input, cep, thoff, flags);
342 cep->flags |= TCP_CEP_FLG_ACK_NOW;
343 }
344 return flags;
345 }
346
347/*
348 * listening -- 受動オープンして,状態が LISTEN の処理
349 *
350 * 戻り値:
351 * RET_OK 正常
352 * RET_DROP エラー、セグメントを破棄する。
353 * RET_RST_DROP エラー、RST を送信し、セグメントを破棄する。
354 */
355
356static ER
357listening (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, T_TCP_SEQ iss)
358{
359 T_TCP_HDR *tcph;
360
361 tcph = GET_TCP_HDR(input, thoff);
362
363 /*
364 * フラグに RST がセットされていれば破棄する。
365 */
366 if (tcph->flags & TCP_FLG_RST)
367 return RET_DROP;
368
369 /*
370 * フラグに ACK がセットさてれいれば、
371 * リセットを送って破棄する。
372 */
373 if (tcph->flags & TCP_FLG_ACK)
374 return RET_RST_DROP;
375
376 /*
377 * フラグに SYN がセットされていなければれば破棄する。
378 */
379 if ((tcph->flags & TCP_FLG_SYN) == 0)
380 return RET_DROP;
381
382 /*
383 * 受信可能な IP アドレスとポート番号であることを確認する。
384 */
385 if (!tcp_is_addr_accept(input, thoff))
386 return RET_DROP;
387
388 /* 相手のアドレスを記録する。*/
389 IN_COPY_TO_HOST(&cep->dstaddr.ipaddr, input);
390 cep->dstaddr.portno = tcph->sport;
391
392 /* オプションを処理する。*/
393 parse_option(tcph, cep);
394
395 /* シーケンス番号を初期化する。*/
396 if (tcp_iss == 0)
397 tcp_init_iss();
398
399 /* 自分のシーケンス番号の初期値を記録する。*/
400 if (iss != 0)
401 cep->iss = iss;
402 else
403 cep->iss = tcp_iss;
404
405 tcp_iss += TCP_ISS_INCR() / 4;
406
407 /* 相手のシーケンス番号の初期値を記録する。*/
408 cep->irs = tcph->seq;
409
410 /* 送受信シーケンス番号を初期化する。*/
411 init_send_seq(cep);
412 init_receive_seq(cep);
413
414 /* 送信ウインドサイズを設定する。*/
415 cep->snd_wnd = tcph->win;
416
417 /* 最終設定 */
418 cep->flags |= TCP_CEP_FLG_ACK_NOW;
419 cep->fsm_state = TCP_FSM_SYN_RECVD;
420 cep->timer[TCP_TIM_KEEP] = TCP_TVAL_KEEP_INIT;
421
422 return RET_OK;
423 }
424
425/*
426 * syn_sent -- 能動オープンして、状態が SYN 送信済の処理
427 *
428 * 戻り値:
429 * RET_OK 正常
430 * RET_DROP エラー、セグメントを破棄する。
431 * RET_RST_DROP エラー、RST を送信し、セグメントを破棄する。
432 */
433
434static ER
435syn_sent (T_TCP_HDR *tcph, T_TCP_CEP *cep)
436{
437 ER error = RET_OK;
438
439 /*
440 * 相手から受信確認が送られて来ても、
441 *
442 * ACK <= iss && 送信した最大 SEQ (snd_max) < ACK
443 *
444 * なら、リセットを送ってセグメントを破棄する。
445 */
446 if ((tcph->flags & TCP_FLG_ACK) &&
447 (SEQ_LE(tcph->ack, cep->iss) || SEQ_GT(tcph->ack, cep->snd_max)))
448 return RET_RST_DROP;
449
450 /*
451 * RST/ACK フラグの応答があれば、ポートが開いていない
452 * ことを意味している。
453 */
454 if (tcph->flags & TCP_FLG_RST) {
455 if (tcph->flags & TCP_FLG_ACK) {
456 cep->net_error = EV_CNNRF;
457 cep = tcp_drop(cep, E_CLS);
458 }
459 return RET_DROP;
460 }
461
462 /*
463 * SYN フラグがなければセグメントを破棄する。
464 */
465 if ((tcph->flags & TCP_FLG_SYN) == 0)
466 return RET_DROP;
467
468 cep->snd_wnd = tcph->win; /* snd_wnd: 相手の受信可能ウィンドサイズ */
469 cep->irs = tcph->seq; /* irs: 相手のシーケンス番号の初期値 */
470 init_receive_seq(cep); /* 送受信シーケンス番号を初期化する。 */
471
472 if (tcph->flags & TCP_FLG_ACK) {
473 /*
474 * ACK フラグがあるときの処理
475 *
476 * 受信を期待している最大の SEQ (rcv_adv) を
477 * 受信可能なウィンドサイズ (rcv_wnd) 分進める。
478 */
479 cep->rcv_adv += cep->rcv_wnd; /* rcv_adv: 受信を期待している最大の SEQ */
480 /* rcv_wnd: 受信可能なウィンドサイズ */
481
482 /* 未確認の最小送信 SEQ (snd_una) を SYN 分 (1 オクテット) 進める。*/
483 cep->snd_una ++;
484
485#ifdef TCP_CFG_DELAY_ACK
486
487 if (tcph->sum != 0) /* tcph->sum は SDU 長 */
488 cep->flags |= TCP_CEP_FLG_DEL_ACK;
489 else
490 cep->flags |= TCP_CEP_FLG_ACK_NOW;
491
492#else/* of #ifdef TCP_CFG_DELAY_ACK */
493
494 cep->flags |= TCP_CEP_FLG_ACK_NOW;
495
496#endif/* of #ifdef TCP_CFG_DELAY_ACK */
497
498 if (cep->flags & TCP_CEP_FLG_NEED_FIN) {
499 /*
500 * CEP で FIN 送信が要求されていれば、
501 * 切断処理を開始し、
502 * CEP の状態を FIN Wait 1 にする。
503 */
504 cep->fsm_state = TCP_FSM_FIN_WAIT_1;
505 cep->flags &= ~TCP_CEP_FLG_NEED_FIN;
506 tcph->flags &= ~TCP_FLG_SYN;
507 }
508 else {
509 /*
510 * 相手から ACK が応答されたので、
511 * CEP の状態を コネクション開設完了状態にする。
512 */
513 cep->timer[TCP_TIM_KEEP] = TCP_TVAL_KEEP_IDLE;
514 cep->fsm_state = TCP_FSM_ESTABLISHED;
515 NET_COUNT_MIB(tcp_stats.tcpActiveOpens, 1);
516 syscall(set_flg(cep->est_flgid, TCP_CEP_EVT_ESTABLISHED));
517
518#ifdef TCP_CFG_NON_BLOCKING
519
520 if (cep->snd_nblk_tfn == TFN_TCP_CON_CEP) {
521
522 /* 相手のアドレスをコピーする。*/
523
524#if defined(_IP6_CFG) && defined(_IP4_CFG)
525
526 if (cep->flags & TCP_CEP_FLG_IPV4) {
527 (*cep->p_dstaddr4).ipaddr = ntohl(cep->dstaddr.ipaddr.s6_addr32[3]);
528 (*cep->p_dstaddr4).portno = cep->dstaddr.portno;
529 }
530 else
531 *cep->p_dstaddr = cep->dstaddr;
532
533#else /* of #if defined(_IP6_CFG) && defined(_IP4_CFG) */
534
535 *cep->p_dstaddr = cep->dstaddr;
536
537#endif /* of #if defined(_IP6_CFG) && defined(_IP4_CFG) */
538
539 if (IS_PTR_DEFINED(cep->callback)) {
540
541#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
542
543 NET_COUNT_TCP(net_count_tcp[NC_TCP_CONNECTS], 1);
544 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, E_OK);
545
546#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
547
548 ER error = E_OK;
549
550 NET_COUNT_TCP(net_count_tcp[NC_TCP_CONNECTS], 1);
551 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)&error);
552
553#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
554
555 }
556 else {
557 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
558 error = RET_RST_DROP;
559 }
560 cep->p_dstaddr = NULL;
561 cep->snd_tskid = TA_NULL;
562 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
563 }
564 else
565
566#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
567
568 NET_COUNT_TCP(net_count_tcp[NC_TCP_CONNECTS], 1);
569 }
570 }
571 else {
572 /* ACK フラグがないときは、ACK を送って、CEP の状態を SYN 受信済みにする。*/
573 cep->flags |= TCP_CEP_FLG_ACK_NOW;
574 cep->timer[TCP_TIM_REXMT] = 0;
575 cep->fsm_state = TCP_FSM_SYN_RECVD;
576 }
577
578 return error;
579 }
580
581/*
582 * trim_length -- 受信した SDU 長を調整する。
583 */
584
585static void
586trim_length (T_TCP_HDR *tcph, T_TCP_CEP *cep)
587{
588 tcph->seq ++;
589 if (tcph->sum > cep->rcv_wnd) { /* 注意: tcph->sum は SDU 長 */
590 /*
591 * SDU 長が受信ウィンドサイズより大きいときは、受信ウィンドサイズ以降は
592 * 破棄し、FIN に応答しないことで、破棄したデータを再送させる。
593 */
594 tcph->sum = (uint16_t)cep->rcv_wnd;
595 tcph->flags &= ~TCP_FLG_FIN;
596 }
597 cep->snd_wl1 = tcph->seq - 1; /* cep->snd_wl1: ウィンド更新 SEQ 番号 */
598
599#ifdef TCP_CFG_EXTENTIONS
600 cep->rcv_up = tcph->seq; /* cep->rcv_up : 受信した緊急ポインタ */
601#endif
602 }
603
604/*
605 * proc_ack2 -- ACK の処理 (2)
606 *
607 * 戻り値
608 *
609 * RET_OK 正常
610 * RET_RETURN 正常、リターンする。
611 * RET_DROP エラー、セグメントを破棄する。
612 * RET_RST_DROP エラー、RST を送信し、セグメントを破棄する。
613 */
614
615static ER
616proc_ack2 (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, bool_t *needoutput)
617{
618 T_TCP_HDR *tcph;
619 ER ret = RET_OK;
620 uint32_t acked;
621 bool_t ourfinisacked = false;
622
623 tcph = GET_TCP_HDR(input, thoff);
624
625 /*
626 * 相手に受信確認された ACK から、まだ確認されていない
627 * 最小送信 SEQ (snd_una) を引くと、送信ウィンドバッファから
628 * 削除してよいオクテット数 (acked) になる。
629 */
630 acked = tcph->ack - cep->snd_una;
631 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_ACKS], 1);
632
633 /*
634 * 往復時間計測 (rtt) が設定されていて、計測開始 SEQ より
635 * 後の ACK を受信したら、タイマバックオフをキャンセルし、
636 * 再送タイマを再設定する。
637 */
638 if (cep->rtt && SEQ_GT(tcph->ack, cep->rtseq)) {
639 set_rexmt_timer(cep, cep->rtt);
640 }
641
642 /*
643 * 全ての未確認データが ACK されたら、再送タイマを停止し、
644 * 再開を記憶する (さらに出力か持続)。
645 * もし、ACK すべき、さらに多くのデータがあるなら、再送タイマに
646 * 現在の再送タイムアウトを設定する。
647 */
648 if (tcph->ack == cep->snd_max) { /* cep->snd_max: 送信した最大 SEQ */
649
650#ifdef TCP_CFG_SWBUF_CSAVE
651
652 /*
653 * 送信ウィンドバッファの省コピー機能が有効の場合は、
654 * 送信済みで、ACKが完了するまで再送タイマを変更しない。
655 */
656 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_ACKED)
657 cep->timer[TCP_TIM_REXMT] = 0;
658
659#else /* of #ifdef TCP_CFG_SWBUF_CSAVE */
660
661 cep->timer[TCP_TIM_REXMT] = 0;
662
663#endif /* of #ifdef TCP_CFG_SWBUF_CSAVE */
664
665 *needoutput = true;
666 }
667 else if (cep->timer[TCP_TIM_PERSIST] == 0) {
668 cep->timer[TCP_TIM_REXMT] = cep->rxtcur; /* cep->rxtcur: 現在の再送タイムアウト */
669 }
670
671 /* 相手が受信確認したデータがあるときの処理 */
672 if (acked) {
673 uint32_t cw = cep->snd_cwnd; /* cep->snd_cwnd: 輻輳ウィンドサイズ */
674 uint32_t incr = cep->maxseg; /* cep->maxseg: 最大セグメントサイズ */
675
676 /*
677 * 新たに相手が受信確認したデータがあったときは、
678 * 輻輳ウィンドサイズを大きくする。
679 * 輻輳ウィンドサイズ (snd_cwnd) が
680 * 輻輳ウィンドサイズのしきい値 (snd_ssthresh) より大きいときは
681 * 輻輳回避制御を行い。
682 *
683 * snd_cwnd = snd_cwnd + maxseg * maxseg / snd_cwnd;
684 *
685 * 等しいか小さいときは、スロースタート制御を行う。
686 *
687 * snd_cwnd = snd_cwnd + maxseg
688 *
689 */
690 if (cw > cep->snd_ssthresh)
691 /* 輻輳回避制御 */
692 incr = incr * incr / cw;
693
694 if (cw + incr < MAX_TCP_WIN_SIZE)
695 cep->snd_cwnd = (uint16_t)(cw + incr);
696 else
697 cep->snd_cwnd = MAX_TCP_WIN_SIZE;
698
699 /*
700 * 送信ウィンドバッファから、相手が受信確認したデータ数 (acked) のデータを削除する。
701 */
702 if (acked > cep->swbuf_count) {
703 cep->snd_wnd -= cep->swbuf_count;
704 TCP_DROP_SWBUF(cep, (uint_t)cep->swbuf_count);
705 ourfinisacked = true;
706 }
707 else {
708 cep->snd_wnd -= (uint16_t)acked;
709 TCP_DROP_SWBUF(cep, (uint_t)acked);
710 ourfinisacked = false;
711 }
712
713 /* 送信ウィンドバッファに空きができたことを知らせる。*/
714 syscall(set_flg(cep->snd_flgid, TCP_CEP_EVT_SWBUF_READY));
715
716 /*
717 * 送達確認されていない最小送信 SEQ (snd_una) を
718 * 今回送達確認された ACK まで進め、
719 * 次の送信データの SEQ (snd_nxt) も、新しい
720 * 送達確認されていない最小送信 SEQ (snd_una)
721 * まで進める。
722 */
723 cep->snd_una += acked;
724 if (SEQ_LT(cep->snd_nxt, cep->snd_una))
725 cep->snd_nxt = cep->snd_una;
726
727 /*
728 * 状態により分岐
729 */
730 switch (cep->fsm_state) {
731 case TCP_FSM_FIN_WAIT_1: /* APP が終了、FIN 送信済み、ACK 待ち */
732 if (ourfinisacked) {
733 cep->fsm_state = TCP_FSM_FIN_WAIT_2;
734 cep->timer[TCP_TIM_2MSL] = TCP_TVAL_KEEP_COUNT * TCP_TVAL_KEEP_INTERVAL;
735 }
736 break;
737 case TCP_FSM_CLOSING: /* 同時クローズ、FIN 交換済み、ACK 待ち */
738 if (ourfinisacked) {
739 /*
740 * 送信した FIN が確認されていれば状態を変更し、
741 * すべてのタイマをリセットした後、2MSL タイマを設定する。
742 */
743 cep->fsm_state = TCP_FSM_TIME_WAIT;
744 tcp_cancel_timers(cep);
745 cep->timer[TCP_TIM_2MSL] = 2 * TCP_TVAL_MSL;
746 }
747 break;
748 case TCP_FSM_LAST_ACK: /* APP が終了、ACK 待ち */
749 if (ourfinisacked) {
750 /*
751 * 送信した FIN が確認されていれば、cep をクローズし、
752 * セグメントを破棄する。
753 */
754 cep = tcp_close(cep);
755 ret = RET_DROP;
756 }
757 break;
758 case TCP_FSM_TIME_WAIT: /* 相手からの FIN 受信済み、時間待ち */
759 /*
760 * 相手から FIN が再送された。もう一度2MSL タイマを設定し、
761 * ACK 送信後、セグメントを破棄する。
762 */
763 cep->timer[TCP_TIM_2MSL] = 2 * TCP_TVAL_MSL;
764 return drop_after_ack(input, cep, thoff);
765 }
766 }
767
768 return ret;
769 }
770
771/*
772 * proc_ack1 -- ACK の処理 (1)
773 *
774 * 戻り値:
775 * RET_OK 正常
776 * RET_RETURN 正常、リターンする。
777 * RET_DROP エラー、セグメントを破棄する。
778 * RET_RST_DROP エラー、RST を送信し、セグメントを破棄する。
779 *
780 */
781
782static ER
783proc_ack1 (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, bool_t *needoutput)
784{
785 T_TCP_HDR *tcph = GET_TCP_HDR(input, thoff);
786
787 switch (cep->fsm_state) {
788 case TCP_FSM_SYN_RECVD: /* SYN を受信し、SYN 送信済み */
789
790 /* 状態を変更する。*/
791 if (cep->flags & TCP_CEP_FLG_NEED_FIN) {
792 cep->fsm_state = TCP_FSM_FIN_WAIT_1;
793 cep->flags &= ~TCP_CEP_FLG_NEED_FIN;
794 }
795 else {
796 cep->timer[TCP_TIM_KEEP] = TCP_TVAL_KEEP_IDLE;
797 cep->fsm_state = TCP_FSM_ESTABLISHED;
798
799 /* TCP 通信端点からTCP 受付口を解放する。*/
800 cep->rep = NULL;
801
802#if defined(_IP6_CFG) && defined(_IP4_CFG)
803 cep->rep4 = NULL;
804#endif
805
806 syscall(set_flg(cep->est_flgid, TCP_CEP_EVT_ESTABLISHED));
807
808#ifdef TCP_CFG_NON_BLOCKING
809
810 if (cep->rcv_nblk_tfn == TFN_TCP_ACP_CEP) {
811
812 /* 相手のアドレスをコピーする。*/
813
814#if defined(_IP6_CFG) && defined(_IP4_CFG)
815
816 if (cep->flags & TCP_CEP_FLG_IPV4) {
817 (*cep->p_dstaddr4).ipaddr = ntohl(cep->dstaddr.ipaddr.s6_addr32[3]);
818 (*cep->p_dstaddr4).portno = cep->dstaddr.portno;
819 }
820 else
821 *cep->p_dstaddr = cep->dstaddr;
822
823#else /* of #if defined(_IP6_CFG) && defined(_IP4_CFG) */
824
825 *cep->p_dstaddr = cep->dstaddr;
826
827#endif /* of #if defined(_IP6_CFG) && defined(_IP4_CFG) */
828
829 if (IS_PTR_DEFINED(cep->callback)) {
830
831#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
832
833 NET_COUNT_MIB(tcp_stats.tcpPassiveOpens, 1);
834 NET_COUNT_TCP(net_count_tcp[NC_TCP_ACCEPTS], 1);
835 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, E_OK);
836
837#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
838
839 ER error = E_OK;
840
841 NET_COUNT_MIB(tcp_stats.tcpPassiveOpens, 1);
842 NET_COUNT_TCP(net_count_tcp[NC_TCP_ACCEPTS], 1);
843 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&error);
844
845#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
846
847 cep->p_dstaddr = NULL;
848 cep->rcv_tskid = TA_NULL;
849 cep->rcv_tfn = cep->rcv_nblk_tfn = TFN_TCP_UNDEF;
850 }
851 else {
852 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
853 cep->p_dstaddr = NULL;
854 cep->rcv_tskid = TA_NULL;
855 cep->rcv_tfn = cep->rcv_nblk_tfn = TFN_TCP_UNDEF;
856 return RET_RST_DROP;
857 }
858 }
859
860 if (cep->snd_nblk_tfn == TFN_TCP_CON_CEP) {
861
862 /* 相手のアドレスをコピーする。*/
863
864#if defined(_IP6_CFG) && defined(_IP4_CFG)
865
866 if (cep->flags & TCP_CEP_FLG_IPV4) {
867 (*cep->p_dstaddr4).ipaddr = ntohl(cep->dstaddr.ipaddr.s6_addr32[3]);
868 (*cep->p_dstaddr4).portno = cep->dstaddr.portno;
869 }
870 else
871 *cep->p_dstaddr = cep->dstaddr;
872
873#else /* of #if defined(_IP6_CFG) && defined(_IP4_CFG) */
874
875 *cep->p_dstaddr = cep->dstaddr;
876
877#endif /* of #if defined(_IP6_CFG) && defined(_IP4_CFG) */
878
879 if (IS_PTR_DEFINED(cep->callback)) {
880
881#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
882
883 NET_COUNT_MIB(tcp_stats.tcpActiveOpens, 1);
884 NET_COUNT_TCP(net_count_tcp[NC_TCP_CONNECTS], 1);
885 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, E_OK);
886
887#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
888
889 ER error = E_OK;
890
891 NET_COUNT_MIB(tcp_stats.tcpActiveOpens, 1);
892 NET_COUNT_TCP(net_count_tcp[NC_TCP_CONNECTS], 1);
893 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)&error);
894
895#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
896
897 cep->p_dstaddr = NULL;
898 cep->snd_tskid = TA_NULL;
899 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
900 }
901 else {
902 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
903 cep->p_dstaddr = NULL;
904 cep->snd_tskid = TA_NULL;
905 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
906 return RET_RST_DROP;
907 }
908 }
909
910#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
911
912 if (cep->rcv_tfn == TFN_TCP_ACP_CEP) {
913 NET_COUNT_MIB(tcp_stats.tcpPassiveOpens, 1);
914 NET_COUNT_TCP(net_count_tcp[NC_TCP_ACCEPTS], 1);
915 }
916
917 if (cep->snd_tfn == TFN_TCP_CON_CEP) {
918 NET_COUNT_MIB(tcp_stats.tcpActiveOpens, 1);
919 NET_COUNT_TCP(net_count_tcp[NC_TCP_CONNECTS], 1);
920 }
921 }
922
923 /*
924 * SDU がなく FIN がついていなければ、tcp_move_ra2rw() を呼出す。
925 */
926 if (tcph->sum == 0 && (tcph->flags & TCP_FLG_FIN) == 0) /* tcph->sum は SDU 長 */
927 tcph->flags = tcp_move_ra2rw(cep, tcph->flags);
928
929 cep->snd_wl1 = tcph->seq - 1; /* snd_wl1: ウィンド更新 SEQ */
930
931 /* break; 下に落ちる。*/
932
933 case TCP_FSM_ESTABLISHED: /* コネクション開設完了 */
934 case TCP_FSM_FIN_WAIT_1: /* 終了して、FIN 送信済み */
935 case TCP_FSM_FIN_WAIT_2: /* 終了、FIN 伝達確認受信、FIN待ち*/
936 case TCP_FSM_CLOSE_WAIT: /* FIN 受信、クローズ待ち */
937 case TCP_FSM_CLOSING: /* 終了、FIN 交換済み、ACK 待ち */
938 case TCP_FSM_LAST_ACK: /* FIN 受信、終了、ACK 待ち */
939 case TCP_FSM_TIME_WAIT: /* 終了、時間待ち */
940
941 if (SEQ_LE(tcph->ack, cep->snd_una)) {
942
943 /*
944 * 受信確認 ACK が 未確認の最小送信 SEQ (snd_una) と同じか以前のときの処理
945 * つまり、多重に ACK を受信したことを意味している。
946 */
947
948 if (tcph->sum == 0 && tcph->win == cep->snd_wnd) { /* tcph->sum は SDU 長 */
949
950 /*
951 * SDU がなく、相手のウィンドサイズが変更されていなければ、
952 * すでに送信したセグメントの中で、ACK (tcph->ack) と
953 * 同じ SEQ から始まるセグメントが、途中で消失した可能性がある。
954 * この場合は、高速再転送と高速リカバリを行う。
955 */
956 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_DUP_ACKS], 1);
957
958 if (cep->timer[TCP_TIM_REXMT] == 0 || tcph->ack != cep->snd_una) {
959
960 /*
961 * 再送タイマがセットされていないとき、
962 * または、ACK (tcph->ack) と未確認の最小送信 SEQが
963 * 一致しないときは、多重 ACK 数を 0 にする。
964 */
965 cep->dupacks = 0;
966 }
967
968 else if (++ cep->dupacks == MAX_TCP_REXMT_THRESH) {
969
970 /*
971 * 多重 ACK 数がしきい値 (標準 3) になったら
972 * 高速再転送処理を開始する。
973 */
974 uint_t win;
975
976 /*
977 * 輻輳ウィンドサイズ(snd_cwnd)のしきい値を設定する。
978 *
979 * 相手の受信可能ウィンドサイズ (snd_wnd) か
980 * 輻輳ウィンドサイズ (snd_cwnd) の 1/2。
981 * ただし、2 * maxseg 以上。
982 *
983 */
984 if (cep->snd_wnd < cep->snd_cwnd)
985 win = cep->snd_wnd / 2 / cep->maxseg;
986 else
987 win = cep->snd_cwnd / 2 / cep->maxseg;
988 if (win < 2)
989 win = 2;
990 cep->snd_ssthresh = win * cep->maxseg;
991
992 /* 再送タイマと往復時間をリセットする。*/
993 cep->timer[TCP_TIM_REXMT] = 0;
994 cep->rtt = 0;
995
996 /* 消失したセグメントを送信する。*/
997 cep->snd_old_nxt = cep->snd_nxt;
998 cep->snd_nxt = tcph->ack;
999 cep->snd_cwnd = cep->maxseg;
1000
1001 /*
1002 * snd_nxt を元に戻すように設定して
1003 * 送信を指示する。
1004 */
1005 cep->flags |= TCP_CEP_FLG_POST_OUTPUT |
1006 TCP_CEP_FLG_FORCE |
1007 TCP_CEP_FLG_FORCE_CLEAR |
1008 TCP_CEP_FLG_RESTORE_NEXT_OUTPUT;
1009 sig_sem(SEM_TCP_POST_OUTPUT);
1010
1011 /* 輻輳ウィンドサイズを更新する。*/
1012 cep->snd_cwnd = (uint16_t)(cep->snd_ssthresh
1013 + cep->maxseg * cep->dupacks);
1014
1015 return RET_DROP;
1016 }
1017
1018 else if (cep->dupacks > MAX_TCP_REXMT_THRESH) {
1019
1020 /*
1021 * 多重 ACK 数がしきい値 (標準 3) を超えたら
1022 * 輻輳ウィンドサイズを増加しながら再送する。
1023 */
1024 cep->snd_cwnd += cep->maxseg;
1025
1026 /* 送信を指示する。*/
1027 cep->flags |= TCP_CEP_FLG_POST_OUTPUT;
1028 sig_sem(SEM_TCP_POST_OUTPUT);
1029
1030 return RET_DROP;
1031 }
1032 }
1033 else
1034 cep->dupacks = 0;
1035 break;
1036 }
1037
1038 /*
1039 * 受信確認 ACK が 未確認の最小送信 SEQ (snd_una) 以降のときの処理
1040 */
1041 if (cep->dupacks >= MAX_TCP_REXMT_THRESH && cep->snd_cwnd > cep->snd_ssthresh)
1042 /*
1043 * 高速再転送を行っていたときは、輻輳ウィンドサイズをしきい値まで戻す。
1044 */
1045 cep->snd_cwnd = (uint16_t)cep->snd_ssthresh;
1046
1047 cep->dupacks = 0;
1048
1049 if (SEQ_GT(tcph->ack, cep->snd_max))
1050 /*
1051 * 受信した ACK が送信した最大 SEQ を超えていたときの処理
1052 */
1053 return drop_after_ack(input, cep, thoff);
1054
1055 if (cep->flags & TCP_CEP_FLG_NEED_SYN) {
1056 /*
1057 * SYN 送信要求を取り消して、未確認の最小送信 SEQ を進める。
1058 */
1059 cep->flags &= ~TCP_CEP_FLG_NEED_SYN;
1060 cep->snd_una ++;
1061 }
1062
1063 return proc_ack2(input, cep, thoff, needoutput);
1064 break;
1065 }
1066 return RET_OK;
1067 }
1068
1069/*
1070 * update_wnd -- ウィンドサイズを更新する。
1071 *
1072 * 戻り値: 送信が必要なら true を返す。
1073 */
1074
1075static bool_t
1076update_wnd (T_TCP_HDR *tcph, T_TCP_CEP *cep)
1077{
1078
1079 /*
1080 * 更新条件
1081 *
1082 * ACK フラグがセットされている &&
1083 * (前回ウィンドを更新した SEQ (snd_wl1) が SEQ より前 ||
1084 * 前回ウィンドを更新した SEQ (snd_wl1) が SEQ と同じ &&
1085 * (前回ウィンドを更新した ACK (snd_wl2) が ACK より前 ||
1086 * (前回ウィンドを更新した ACK (snd_wl2) が ACK と同じ &&
1087 * WIN が相手の受信可能ウィンドサイズ (snd_wnd) より大きい
1088 * )
1089 * )
1090 * )
1091 */
1092 if ((tcph->flags & TCP_FLG_ACK) &&
1093 (SEQ_LT(cep->snd_wl1, tcph->seq) ||
1094 (cep->snd_wl1 == tcph->seq &&
1095 (SEQ_LT(cep->snd_wl2, tcph->ack) ||
1096 (cep->snd_wl2 == tcph->ack && tcph->win > cep->snd_wnd))))) {
1097
1098 cep->snd_wnd = tcph->win;
1099 cep->snd_wl1 = tcph->seq;
1100 cep->snd_wl2 = tcph->ack;
1101
1102 if (cep->snd_wnd > cep->max_sndwnd)
1103 /* 今までの最大送信ウィンドサイズを更新する。*/
1104 cep->max_sndwnd = cep->snd_wnd;
1105
1106#ifdef TCP_CFG_SWBUF_CSAVE
1107
1108 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_WOPEN_PEND) {
1109
1110 /*
1111 * 送信ウィンドバッファ用のネットワークバッファ割り当て中で、
1112 * 相手の受信ウィンドが空くのを待っているときの処理
1113 */
1114 if (cep->snd_wnd > 0) {
1115
1116 /*
1117 * 相手の受信ウィンドが空いたときは、
1118 * 送信ウィンドバッファ用のネットワークバッファ割り当てを再開する。
1119 */
1120 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK)
1121 | TCP_CEP_FLG_WBCS_FREE | TCP_CEP_FLG_POST_OUTPUT;
1122 sig_sem(SEM_TCP_POST_OUTPUT);
1123 }
1124 }
1125
1126#endif /* of #ifdef TCP_CFG_SWBUF_CSAVE */
1127
1128 return true;
1129 }
1130 else
1131 return false;
1132 }
1133
1134/*
1135 * proc_urg -- 緊急データつきのセグメントの処理
1136 */
1137
1138#ifdef TCP_CFG_EXTENTIONS
1139
1140static void
1141proc_urg (T_TCP_HDR *tcph, T_TCP_CEP *cep)
1142{
1143 if ((tcph->flags & TCP_FLG_URG) && VALID_URG_POINTER(tcph->urp) &&
1144 TCP_FSM_HAVE_RCVD_FIN(cep->fsm_state) == 0) {
1145
1146 /* 緊急データつきのセグメントの処理 */
1147
1148 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_URG_SEGS], 1);
1149 if (tcph->urp + cep->rwbuf_count > cep->rbufsz) {
1150
1151 /*
1152 * 緊急ポインタの位置が受信ウィンドバッファの
1153 * 範囲を超えるときは何もしない。
1154 */
1155 tcph->urp = 0;
1156 tcph->flags &= ~TCP_FLG_URG;
1157 }
1158
1159 if (SEQ_GT(tcph->seq + tcph->urp, cep->rcv_up))
1160 /* 緊急ポインタが更新されたときの処理 */
1161 cep->rcv_up = tcph->seq + tcph->urp;
1162
1163 if ((tcph->flags & TCP_FLG_URG) && (tcph->urp + TCP_CFG_URG_OFFSET) < tcph->sum) { /* tcph->sum は TCP の SDU 長 */
1164
1165 /*
1166 * 緊急ポインタの位置が、今回受信したセグメント内の場合は、
1167 * コールバック関数を呼び出す。
1168 */
1169 cep->urg_tcph = tcph;
1170 if (IS_PTR_DEFINED(cep->callback)) {
1171
1172#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
1173
1174 (*cep->callback)(GET_TCP_CEPID(cep), TEV_TCP_RCV_OOB, (void*)(uint32_t)1);
1175
1176#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
1177
1178 uint32_t len = 1;
1179
1180 (*cep->callback)(GET_TCP_CEPID(cep), TEV_TCP_RCV_OOB, (void*)&len);
1181
1182#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
1183
1184 }
1185 else {
1186 syslog(LOG_WARNING, "[TCP] no call back for OOB, CEP: %d.", GET_TCP_CEPID(cep));
1187 }
1188
1189 if (cep->urg_tcph != NULL) {
1190 /* コールバック関数内で tcp_rcv_oob() を呼出さなかった。*/
1191 cep->urg_tcph = NULL;
1192 tcph->urp = 0;
1193 }
1194 else {
1195 /*
1196 * コールバック関数内で tcp_rcv_oob() を呼出した時は、
1197 * SDU 長の補正値を設定する。
1198 */
1199 tcph->urp = 1;
1200 }
1201 }
1202 else if (tcph->urp > 0) {
1203 tcph->urp = 0;
1204 }
1205
1206 }
1207 else if (SEQ_GT(cep->rcv_nxt, cep->rcv_up)) {
1208 cep->rcv_up = cep->rcv_nxt;
1209 tcph->urp = 0;
1210 }
1211 }
1212
1213#else /* of #ifdef TCP_CFG_EXTENTIONS */
1214
1215static void
1216proc_urg (T_TCP_HDR *tcph, T_TCP_CEP *cep)
1217{
1218 tcph->urp = 0;
1219 }
1220
1221#endif /* of #ifdef TCP_CFG_EXTENTIONS */
1222
1223/*
1224 * drop_after_ack -- 受信セグメントを破棄した後、ACK を返す (注意: 名前とは合っていない)。
1225 *
1226 * 戻り値:
1227 * RET_RETURN 正常、リターンする。
1228 * RET_RST_DROP エラー、RST を送信し、セグメントを破棄する。
1229 */
1230
1231static ER
1232drop_after_ack (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff)
1233{
1234 T_TCP_HDR *tcph = GET_TCP_HDR(input, thoff);
1235
1236 /*
1237 * SYN 受信状態で、ACK が送達確認されていない最小送信 SEQ (snd_una) より
1238 * 前の値か、送信された最大 SEQ (snd_max) より後の値の場合は、相手に RST を
1239 * 送って終了する。これは、"LAND" DoS 攻撃への防御であり、偽造された SYN
1240 * セグメントを送信しつづけるポート間での ACK ストームを防ぐ。
1241 */
1242 if (cep->fsm_state == TCP_FSM_SYN_RECVD && (tcph->flags & TCP_FLG_ACK) &&
1243 (SEQ_GT(cep->snd_una, tcph->ack) ||
1244 SEQ_GT(tcph->ack, cep->snd_max)))
1245 return RET_RST_DROP;
1246
1247 syscall(rel_net_buf(input));
1248
1249 /* 送信を指示する。*/
1250 cep->flags |= TCP_CEP_FLG_ACK_NOW | TCP_CEP_FLG_POST_OUTPUT;
1251 sig_sem(SEM_TCP_POST_OUTPUT);
1252 return RET_RETURN;
1253 }
1254
1255/*
1256 * close_connection -- コネクション開放処理、相手から FIN を受信した。
1257 */
1258
1259static void
1260close_connection (T_TCP_CEP *cep, bool_t *needoutput)
1261{
1262 if (TCP_FSM_HAVE_RCVD_FIN(cep->fsm_state) == 0) {
1263
1264#ifdef TCP_CFG_DELAY_ACK
1265
1266 if (cep->flags & TCP_CEP_FLG_NEED_SYN)
1267 cep->flags |= TCP_CEP_FLG_DEL_ACK;
1268 else
1269 cep->flags |= TCP_CEP_FLG_ACK_NOW;
1270
1271#else/* of #ifdef TCP_CFG_DELAY_ACK */
1272
1273 cep->flags |= TCP_CEP_FLG_ACK_NOW;
1274
1275#endif/* of #ifdef TCP_CFG_DELAY_ACK */
1276
1277 cep->rcv_nxt ++;
1278 }
1279
1280 switch (cep->fsm_state) {
1281 case TCP_FSM_SYN_RECVD: /* SYN を受信し、SYN 送信済み */
1282 case TCP_FSM_ESTABLISHED: /* コネクション開設完了 */
1283 cep->fsm_state = TCP_FSM_CLOSE_WAIT;
1284 syscall(set_flg(cep->snd_flgid, TCP_CEP_EVT_RWBUF_READY));
1285 break;
1286
1287 case TCP_FSM_FIN_WAIT_1: /* APP が終了、FIN 送信済み、ACK 待ち */
1288 cep->fsm_state = TCP_FSM_CLOSING;
1289 break;
1290
1291 case TCP_FSM_FIN_WAIT_2: /* 相手からの FIN 待ち */
1292 cep->fsm_state = TCP_FSM_TIME_WAIT;
1293 tcp_cancel_timers(cep);
1294 cep->timer[TCP_TIM_2MSL] = 2 * TCP_TVAL_MSL;
1295
1296 /*
1297 * FIN WAIT 2 状態では、
1298 * 受信は可能であるが、すでに送信は終了している。
1299 * 相手の送信も終了したので、入力タスクのみ起床する。
1300 */
1301 syscall(set_flg(cep->snd_flgid, TCP_CEP_EVT_SWBUF_READY));
1302
1303#if defined(NUM_TCP_TW_CEP_ENTRY) && NUM_TCP_TW_CEP_ENTRY > 0
1304
1305 /* 相手からの FIN に対して応答を返す。*/
1306 tcp_respond(NULL, cep, cep->rcv_nxt, cep->snd_una,
1307 cep->rbufsz - cep->rwbuf_count, TCP_FLG_ACK);
1308 cep->flags &= ~TCP_CEP_FLG_ACK_NOW;
1309 *needoutput = false;
1310
1311 /*
1312 * 必要な情報を Time Wait 用 TCP 通信端点に移して、
1313 * 標準の TCP 通信端点を開放する。
1314 */
1315 tcp_move_twcep(cep);
1316
1317#endif /* of #if defined(NUM_TCP_TW_CEP_ENTRY) && NUM_TCP_TW_CEP_ENTRY > 0 */
1318
1319 break;
1320
1321 case TCP_FSM_TIME_WAIT: /* 相手からの FIN 受信済み、時間待ち */
1322 cep->timer[TCP_TIM_2MSL] = 2 * TCP_TVAL_MSL;
1323 break;
1324 }
1325 }
1326
1327/*
1328 * tcp_input -- TCP の入力関数
1329 *
1330 * 注意: input には IF ヘッダと IP ヘッダが先頭にある。
1331 */
1332
1333uint_t
1334tcp_input (T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
1335{
1336 T_NET_BUF *input = *inputp;
1337 T_TCP_HDR *tcph;
1338 T_TCP_CEP *cep = NULL;
1339 T_TCP_SEQ iss = 0;
1340 ER ret;
1341 bool_t needoutput = false;
1342 int_t rbfree;
1343 int32_t todrop, win;
1344 uint16_t seglen;
1345 uint8_t flags;
1346
1347#if defined(NUM_TCP_TW_CEP_ENTRY) && NUM_TCP_TW_CEP_ENTRY > 0
1348 T_TCP_TWCEP *twcep;
1349#endif /* of #if defined(NUM_TCP_TW_CEP_ENTRY) && NUM_TCP_TW_CEP_ENTRY > 0 */
1350
1351 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_OCTETS],
1352 input->len - GET_IF_IP_HDR_SIZE(input));
1353 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_SEGS], 1);
1354 NET_COUNT_MIB(tcp_stats.tcpInSegs, 1);
1355
1356 /* ヘッダ長をチェックする。*/
1357 if (input->len < IF_IP_TCP_HDR_SIZE(input)) {
1358 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_BAD_HEADERS], 1);
1359 goto drop;
1360 }
1361
1362 tcph = GET_TCP_HDR(input, *offp);
1363
1364 seglen = input->len - *offp; /* TCP のセグメント長 */
1365
1366 if (IN_CKSUM(input, IPPROTO_TCP, *offp, (uint_t)seglen) != 0) {
1367 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_BAD_CKSUMS], 1);
1368 goto drop;
1369 }
1370
1371 /* TCP ヘッダ長をチェックする。*/
1372 if (TCP_HDR_LEN(tcph->doff) < TCP_HDR_SIZE || TCP_HDR_LEN(tcph->doff) > seglen) {
1373 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_BAD_HEADERS], 1);
1374 goto drop;
1375 }
1376 tcph->sum = seglen - TCP_HDR_LEN(tcph->doff); /* ここから tcph->sum は TCP の SDU 長 */
1377
1378 /*
1379 * SYN と FIN の両ビットがセットされていれば破棄する。nmap 等の対策
1380 * ただし、RFC1644 T/TCP 拡張機能と競合する。
1381 */
1382 if ((tcph->flags & (TCP_FLG_SYN | TCP_FLG_FIN)) == (TCP_FLG_SYN | TCP_FLG_FIN))
1383 goto drop;
1384
1385 /* ネットワークオーダーからホストオーダーに変換する。*/
1386
1387 NTOHL(tcph->seq);
1388 NTOHL(tcph->ack);
1389 NTOHS(tcph->win);
1390 NTOHS(tcph->urp);
1391 NTOHS(tcph->sport);
1392 NTOHS(tcph->dport);
1393
1394 /* SDU 長 より 緊急ポインタが大きい場合 */
1395 if (tcph->urp > tcph->sum)
1396 goto drop;
1397
1398find_cep:
1399
1400#if defined(NUM_TCP_TW_CEP_ENTRY) && NUM_TCP_TW_CEP_ENTRY > 0
1401
1402 /*
1403 * 状態が Time Wait 中の CEP を探索する。
1404 */
1405 twcep = tcp_find_twcep(input, *offp);
1406 if (twcep != NULL) {
1407
1408 if (tcph->flags & TCP_FLG_RST) /* RST フラグを受信したときは無視する。*/
1409 goto drop;
1410 else {
1411
1412 /*
1413 * TCP 通信端点が Time Wait の時、相手ホストからセグメントが来たときは、
1414 * 相手ホストの FIN に対する自ホストの ACK セグメントが途中で
1415 * 損失したことを意味しているので、ACK セグメントを再送する。
1416 */
1417
1418 /* ホストオーダーからネットワークオーダーに戻す。*/
1419 HTONS(tcph->sport);
1420 HTONS(tcph->dport);
1421
1422 tcp_respond(input, NULL, twcep->rcv_nxt, twcep->snd_una, twcep->rbufsz - twcep->rwbuf_count, TCP_FLG_ACK);
1423 }
1424 return IPPROTO_DONE;
1425 }
1426 else
1427 /* 標準の TCP 通信端点を得る。*/
1428 cep = tcp_find_cep(input, *offp);
1429
1430#else /* of #if defined(NUM_TCP_TW_CEP_ENTRY) && NUM_TCP_TW_CEP_ENTRY > 0 */
1431
1432 /* TCP 通信端点を得る。*/
1433 cep = tcp_find_cep(input, *offp);
1434
1435#endif /* of #if defined(NUM_TCP_TW_CEP_ENTRY) && NUM_TCP_TW_CEP_ENTRY > 0 */
1436
1437 /*
1438 * TCP 通信端点がない場合と CEP の状態がクローズなら破棄する。
1439 */
1440 if (cep == NULL) {
1441 syslog(LOG_INFO, "[TCP] unexp port: %d.", tcph->dport);
1442 goto reset_drop;
1443 }
1444
1445#ifdef TCP_CFG_TRACE
1446
1447 tcp_input_trace(input, cep);
1448
1449#endif /* of #ifdef TCP_CFG_TRACE */
1450
1451
1452 if (cep->fsm_state == TCP_FSM_CLOSED)
1453 goto drop;
1454
1455 /*
1456 * コネクション開設済みでセグメントを受信したときは、
1457 * アイドル時間と生存確認タイマをリセットする。
1458 */
1459 cep->idle = 0;
1460 if (TCP_FSM_HAVE_ESTABLISHED(cep->fsm_state)) {
1461 cep->timer[TCP_TIM_KEEP] = TCP_TVAL_KEEP_IDLE;
1462 }
1463
1464 /* CEP の状態が LISTEN 以外の時は、オプションを処理する。*/
1465 if (cep->fsm_state != TCP_FSM_LISTEN)
1466 parse_option(tcph, cep);
1467
1468 /*
1469 * 受信可能ウィンドサイズを計算する。
1470 *
1471 * rcv_nxt: 受信を期待している最小の SEQ(これ以前は受信済み)
1472 * rcv_adv: 受信を期待している最大の SEQ
1473 * rbufsz: 受信ウィンドバッファサイズ
1474 * rwbuf_count: 受信ウィンドバッファにあるデータ量
1475 * tcph->sum: 今回受信した SDU サイズ
1476 *
1477 * 今回受信したセグメントを順序整列キューに連結する
1478 * 可能性があるので tcph->sum を考慮する。
1479 *
1480 */
1481 win = cep->rbufsz - (cep->rwbuf_count + tcph->sum);
1482 if (win < 0)
1483 win = 0;
1484 if (win > (int32_t)(cep->rcv_adv - cep->rcv_nxt))
1485 cep->rcv_wnd = win;
1486 else
1487 cep->rcv_wnd = cep->rcv_adv - cep->rcv_nxt;
1488
1489 /* CEP の状態により処理を行う。*/
1490
1491 if (cep->fsm_state == TCP_FSM_LISTEN) { /* 受動オープン (LISTEN) の処理。*/
1492 if ((ret = listening(input, cep, *offp, iss)) == RET_RST_DROP)
1493 goto reset_drop;
1494 else if (ret == RET_DROP)
1495 goto drop;
1496 trim_length(tcph, cep); /* 受信した SDU 長を調整する。*/
1497
1498 if (tcph->flags & TCP_FLG_ACK) { /* ACK フラグの処理 */
1499 if ((ret = proc_ack2(input, cep, *offp, &needoutput)) == RET_DROP)
1500 goto drop;
1501 else if (ret == RET_RST_DROP)
1502 goto reset_drop;
1503 else if (ret == RET_RETURN)
1504 return IPPROTO_DONE;
1505 }
1506 }
1507 else if (cep->fsm_state == TCP_FSM_SYN_SENT) { /* 能動オープン、SYN 送信済み */
1508 if ((ret = syn_sent(tcph, cep)) == RET_RST_DROP)
1509 goto reset_drop;
1510 else if (ret == RET_DROP)
1511 goto drop;
1512 trim_length(tcph, cep); /* 受信した SDU 長を調整する。*/
1513
1514 if (tcph->flags & TCP_FLG_ACK) { /* ACK フラグの処理 */
1515 if ((ret = proc_ack2(input, cep, *offp, &needoutput)) == RET_DROP)
1516 goto drop;
1517 else if (ret == RET_RST_DROP)
1518 goto reset_drop;
1519 else if (ret == RET_RETURN)
1520 return IPPROTO_DONE;
1521 }
1522 }
1523 else {
1524 if (cep->fsm_state == TCP_FSM_SYN_RECVD) { /* SYN を受信、SYN 送信済み */
1525 /*
1526 * 相手から受信確認が送られて来ても、
1527 *
1528 * ACK <= 未確認の最小送信 SEQ (snd_una) &&
1529 * 送信した最大 SEQ (snd_max) < ACK
1530 *
1531 * なら、リセットを送ってセグメントを破棄する。
1532 */
1533 if ((tcph->flags & TCP_FLG_ACK) &&
1534 (SEQ_LE(tcph->ack, cep->snd_una) ||
1535 SEQ_GT(tcph->ack, cep->snd_max)))
1536 goto reset_drop;
1537 }
1538
1539 /*
1540 * RST フラグを受信したときの処理 (異常切断)
1541 */
1542 if (tcph->flags & TCP_FLG_RST) {
1543 if (SEQ_GE(tcph->seq, cep->last_ack_sent) &&
1544 SEQ_LT(tcph->seq, cep->last_ack_sent + cep->rcv_wnd)) {
1545 /*
1546 * 受信したセグメントの SEQ が、最後に送信した ACK (last_ack_sent)
1547 * から、受信ウインドウサイズまでの間の処理
1548 */
1549 switch (cep->fsm_state) {
1550 case TCP_FSM_SYN_RECVD: /* SYN を受信し、SYN 送信済み */
1551
1552 cep->net_error = EV_CNNRF; /* 接続不能 */
1553 cep->error = E_CLS;
1554 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_RSTS], 1);
1555 NET_COUNT_MIB(tcp_stats.tcpAttemptFails, 1);
1556 cep = tcp_close(cep);
1557 break;
1558
1559 case TCP_FSM_ESTABLISHED: /* コネクション開設完了 */
1560 case TCP_FSM_CLOSE_WAIT: /* FIN 受信、クローズ待ち */
1561 NET_COUNT_MIB(tcp_stats.tcpEstabResets, 1);
1562 /* fallthrough */
1563
1564 case TCP_FSM_FIN_WAIT_1: /* 終了して、FIN 送信済み */
1565 case TCP_FSM_FIN_WAIT_2: /* 終了、FIN 伝達確認受信、FIN待ち */
1566
1567 cep->net_error = EV_CNRST; /* 接続リセット */
1568 cep->error = E_CLS;
1569 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_RSTS], 1);
1570 /* no break; */
1571
1572 case TCP_FSM_CLOSING: /* 終了、FIN 交換済み、ACK 待ち */
1573 case TCP_FSM_LAST_ACK: /* FIN 受信、終了、ACK 待ち */
1574
1575 cep = tcp_close(cep);
1576 break;
1577 }
1578 }
1579 goto drop;
1580 }
1581
1582 /*
1583 * CEP の状態が SYN を受信し、SYN 送信済みの場合は、
1584 * 受信ウィンドに収まるようにデータを
1585 * 調整する前に、この接続によるパケットかどうかを検証する。
1586 *
1587 * 受信した相手の SEQ < 相手の SEQ の初期値 (irs)
1588 *
1589 * これは、"LAND" DoS 攻撃の防御である。
1590 */
1591 if (cep->fsm_state == TCP_FSM_SYN_RECVD && SEQ_LT(tcph->seq, cep->irs)) {
1592 goto reset_drop;
1593 }
1594
1595 /*
1596 * 受信を期待している最小の SEQ (rcv_nxt) - 受信した相手の SEQ が
1597 * 正なら、rcv_nxt 以前のデータはすでに受信しているので、その部分を
1598 * 削除する。
1599 * <---------- rcv_wnd --------->
1600 * rcv_nxt rcv_nxt + rcv_wnd
1601 * v v
1602 * -----+----------------------------+-----
1603 * | |
1604 * -----+----------------------------+-----
1605 * +----------------------+
1606 * |***************| |
1607 * +----------------------+
1608 * ^ ^
1609 * seq seq + len
1610 * <---------------> 削除する。
1611 */
1612 todrop = cep->rcv_nxt - tcph->seq;
1613 if (todrop > 0) {
1614
1615 /*
1616 * SYN フラグがついているときは、その分 (1 オクテット)
1617 * SEQ を進め、緊急ポインタと削除する長さを調整する。
1618 */
1619 if (tcph->flags & TCP_FLG_SYN) {
1620 tcph->flags &= ~TCP_FLG_SYN;
1621 tcph->seq ++;
1622 if (tcph->urp > 1)
1623 tcph->urp --;
1624 else
1625 tcph->flags &= ~TCP_FLG_URG;
1626 todrop --;
1627 }
1628
1629 /*
1630 * 削除する長さが SDU より長い、つまり、受信を期待している
1631 * 最小の SEQ (rcv_nxt) に達していないか、
1632 * 削除する長さが SDU と同じで、FIN フラグがついてなければ
1633 * 全て削除する。
1634 */
1635 if ( todrop > tcph->sum || /* tcph->sum は TCP の SDU 長 */
1636 (todrop == tcph->sum && (tcph->flags & TCP_FLG_FIN) == 0)) {
1637 tcph->flags &= ~TCP_FLG_FIN;
1638 cep->flags |= TCP_CEP_FLG_ACK_NOW;
1639 todrop = tcph->sum; /* tcph->sum は TCP の SDU 長 */
1640 }
1641
1642 /*
1643 * SDU を前に詰める。
1644 */
1645 if (todrop < tcph->sum) { /* tcph->sum は TCP の SDU 長 */
1646 memcpy(GET_TCP_SDU(input, *offp),
1647 GET_TCP_SDU(input, *offp) + todrop, (size_t)(tcph->sum - todrop));
1648 }
1649
1650 /*
1651 * SEQ と SDU 長を調整する。
1652 */
1653 tcph->seq += todrop;
1654 tcph->sum -= (uint16_t)todrop; /* tcph->sum は TCP の SDU 長 */
1655
1656 /*
1657 * 緊急ポインタを調整する。
1658 */
1659 if (tcph->urp > todrop)
1660 tcph->urp -= (uint16_t)todrop;
1661 else {
1662 tcph->flags &= ~TCP_FLG_URG;
1663 tcph->urp = 0;
1664 }
1665
1666 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_DUP_SEGS], 1);
1667 }
1668
1669 /*
1670 * もしユーザタスクが終了した後に、データを受信した
1671 * 場合は、RST を送る。
1672 */
1673 if (cep->fsm_state == TCP_FSM_LAST_ACK && tcph->sum > 0) { /* tcph->sum は TCP の SDU 長 */
1674 cep = tcp_close(cep);
1675 goto reset_drop;
1676 }
1677
1678 /*
1679 * 受信セグメントが受信ウィンドを超える場合は、
1680 * 超えた分を削る。
1681 *
1682 * <---------- rcv_wnd --------->
1683 * rcv_nxt (rcv_nxt + rcv_wnd)
1684 * v v
1685 * -----+----------------------------+-----
1686 * | |
1687 * -----+----------------------------+-----
1688 * +----------------------+
1689 * | |******|
1690 * +----------------------+
1691 * ^ ^
1692 * seq seq + len
1693 * <-----> 削除する。
1694 */
1695 todrop = (tcph->seq + tcph->sum) - (cep->rcv_nxt + cep->rcv_wnd); /* tcph->sum は TCP の SDU 長 */
1696 if (todrop > 0) {
1697 if (todrop > tcph->sum) { /* tcph->sum は TCP の SDU 長 */
1698 /*
1699 * 受信した SDU の全てが受信ウィンドを超える場合。
1700 *
1701 * TIME_WAIT 中に、新たな接続要求を受信したら
1702 * 古い接続を破棄し、新たな接続を開始する。
1703 * ただし、SEQ は前より進んでいなければならない。
1704 */
1705 if ((tcph->flags & TCP_FLG_SYN) &&
1706 cep->fsm_state == TCP_FSM_TIME_WAIT &&
1707 SEQ_GT(tcph->seq, cep->rcv_nxt)) {
1708 iss = cep->snd_nxt + TCP_ISS_INCR();
1709 tcp_close(cep);
1710 syscall(dly_tsk(0));
1711 goto find_cep;
1712 }
1713
1714 /*
1715 * 受信ウィンドが 0 で、受信した SEQ と
1716 * 受信を期待している最小の SEQ が一致したときは
1717 * ACK を返す。それ以外はデータを破棄し、ACK を返す。
1718 */
1719 if (cep->rcv_wnd == 0 && (tcph->seq == cep->rcv_nxt || tcph->sum == 0)) {
1720 cep->flags |= TCP_CEP_FLG_ACK_NOW;
1721 }
1722 else if (drop_after_ack(input, cep, *offp) == RET_RST_DROP)
1723 goto reset_drop;
1724 else {
1725 return IPPROTO_DONE;
1726 }
1727 }
1728 tcph->sum -= (uint16_t)todrop; /* tcph->sum は TCP の SDU 長 */
1729 tcph->flags &= ~(TCP_FLG_PUSH | TCP_FLG_FIN);
1730 }
1731
1732 /*
1733 * もし、SYN がセットされていれば、
1734 * エラーなので RST を送り、接続を破棄する。
1735 */
1736 if (tcph->flags & TCP_FLG_SYN) {
1737 cep->net_error = EV_CNRST;
1738 cep = tcp_drop(cep, E_CLS);
1739 goto reset_drop;
1740 }
1741
1742 /*
1743 * もし、ACK がセットされていない場合は、
1744 * 状態が SYN 受信済みか
1745 * SYN を送信しようとしていれば、処理を続けるが、
1746 * それ以外はセグメントを破棄して終了する。
1747 */
1748 if ((tcph->flags & TCP_FLG_ACK) == 0) {
1749 if (!(cep->fsm_state == TCP_FSM_SYN_RECVD || (cep->flags & TCP_CEP_FLG_NEED_SYN)))
1750 goto drop;
1751 }
1752 else {
1753 /*
1754 * ACK の処理
1755 */
1756 ret = proc_ack1(input, cep, *offp, &needoutput);
1757 if (ret == RET_DROP)
1758 goto drop;
1759 else if (ret == RET_RST_DROP)
1760 goto reset_drop;
1761 else if (ret == RET_RETURN)
1762 return IPPROTO_DONE;
1763 }
1764 }
1765
1766/* step 6 */
1767
1768 /* 送信ウィンドを更新する。*/
1769 if (update_wnd(tcph, cep) == true)
1770 needoutput = true;
1771
1772 /* 緊急データを処理する。*/
1773 proc_urg(tcph, cep);
1774
1775/* do data */
1776
1777 /*
1778 * SDU があるか、FIN を未受信の状態で、最初に FIN を受信したとき、
1779 * 受信セグメントキューに net_buf を追加する。
1780 * それ以外の場合は、セグメントを破棄する。
1781 */
1782 flags = tcph->flags;
1783 if ((tcph->sum > 0 || (flags & TCP_FLG_FIN)) && /* tcph->sum は TCP の SDU 長 */
1784 TCP_FSM_HAVE_RCVD_FIN(cep->fsm_state) == 0) {
1785 flags = reassemble(input, cep, *offp, flags);
1786 }
1787 else {
1788 syscall(rel_net_buf(input));
1789 flags &= ~TCP_FLG_FIN;
1790 }
1791
1792 /*
1793 * FIN を受信したらコネクションをクローズする。
1794 */
1795 if (flags & TCP_FLG_FIN)
1796 close_connection(cep, &needoutput);
1797
1798 /* 出力を行った後終了する。*/
1799 if (needoutput == true || (cep->flags & TCP_CEP_FLG_ACK_NOW)) {
1800 /* 送信を指示する。*/
1801 cep->flags |= TCP_CEP_FLG_POST_OUTPUT;
1802 sig_sem(SEM_TCP_POST_OUTPUT);
1803 }
1804
1805 return IPPROTO_DONE;
1806
1807reset_drop:
1808 /*
1809 * RST 送信処理
1810 */
1811
1812 if ((tcph->flags & TCP_FLG_RST) || IN_IS_NET_ADDR_MULTICAST(input))
1813 goto drop;
1814
1815 /* ホストオーダーからネットワークオーダーに戻す。*/
1816
1817 HTONS(tcph->sport);
1818 HTONS(tcph->dport);
1819
1820 if (cep == NULL)
1821 rbfree = 0;
1822 else
1823 rbfree = cep->rbufsz - cep->rwbuf_count;
1824
1825 if (tcph->flags & TCP_FLG_ACK)
1826 tcp_respond(input, cep, 0, tcph->ack, rbfree, TCP_FLG_RST);
1827 else {
1828 if (tcph->flags & TCP_FLG_SYN)
1829 tcph->sum ++; /* tcph->sum は SDU 長 */
1830 tcp_respond(input, cep, tcph->seq + tcph->sum, 0, rbfree, TCP_FLG_RST | TCP_FLG_ACK);
1831 }
1832
1833 /* input は tcp_respoond で返却される。*/
1834 NET_COUNT_TCP(net_count_tcp[NC_TCP_SEND_RSTS], 1);
1835 NET_COUNT_MIB(tcp_stats.tcpOutRsts, 1);
1836 return IPPROTO_DONE;
1837
1838drop:
1839 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_DROP_SEGS], 1);
1840 NET_COUNT_MIB(tcp_stats.tcpInErrs, 1);
1841 syscall(rel_net_buf(input));
1842 return IPPROTO_DONE;
1843 }
1844
1845#endif /* of #ifdef SUPPORT_TCP */
Note: See TracBrowser for help on using the repository browser.