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