source: EcnlProtoTool/trunk/asp3_dcre/tinet/netinet/tcp_input.c@ 270

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

mruby版ECNLプロトタイピング・ツールを追加

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