source: azure_iot_hub/trunk/asp3_dcre/tinet/netinet/tcp_input.c@ 388

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

Azure IoT Hub Device C SDK を使ったサンプルの追加

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