source: rubycfg_asp/trunk/asp_dcre/tinet/netinet/tcp_output.c@ 313

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

ソースを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 34.8 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_output.c 313 2017-07-23 04:50:32Z coas-nagasima $
44 */
45
46/*
47 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 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_output.c 8.4 (Berkeley) 5/24/95
79 * $FreeBSD: src/sys/netinet/tcp_output.c,v 1.32.2.2 1999/08/29 16:29:55 peter Exp $
80 */
81
82#ifdef TARGET_KERNEL_ASP
83
84#include <kernel.h>
85#include <sil.h>
86#include <t_syslog.h>
87#include "kernel_cfg.h"
88
89#endif /* of #ifdef TARGET_KERNEL_ASP */
90
91#ifdef TARGET_KERNEL_JSP
92
93#include <s_services.h>
94#include <t_services.h>
95#include "kernel_id.h"
96
97#endif /* of #ifdef TARGET_KERNEL_JSP */
98
99#include <tinet_defs.h>
100#include <tinet_config.h>
101
102#include <net/if.h>
103#include <net/if_ppp.h>
104#include <net/if_loop.h>
105#include <net/ethernet.h>
106#include <net/net.h>
107#include <net/net_endian.h>
108#include <net/net_var.h>
109#include <net/net_buf.h>
110#include <net/net_timer.h>
111#include <net/net_count.h>
112
113#include <netinet/in.h>
114#include <netinet/in_var.h>
115#include <netinet/in_itron.h>
116#include <netinet/ip.h>
117#include <netinet/ip_var.h>
118#include <netinet/tcp.h>
119#include <netinet/tcp_var.h>
120#include <netinet/tcp_fsm.h>
121#include <netinet/tcp_seq.h>
122#include <netinet/tcp_timer.h>
123
124#ifdef SUPPORT_TCP
125
126/*
127 * 関数
128 */
129
130static ER send_segment (bool_t *sendalot, T_TCP_CEP *cep, uint_t doff, uint_t win, uint_t len, uint8_t flags);
131static void tcp_output (T_TCP_CEP *cep);
132
133/*
134 * 変数
135 */
136
137/* 出力時のフラグを FSM 状æ…
138‹ã«ã‚ˆã‚Šé¸æŠžã™ã‚‹ãŸã‚ã®è¡¨ */
139
140const static uint8_t tcp_outflags[] = {
141 TCP_FLG_RST | TCP_FLG_ACK, /* 0, クローズ */
142 0, /* 1, 受動オープン */
143 TCP_FLG_SYN, /* 2, 能動オープン、SYN 送信済み */
144 TCP_FLG_SYN | TCP_FLG_ACK, /* 3, SYM を受信し、SYN 送信済み */
145 TCP_FLG_ACK, /* 4, コネクション開設完了 */
146 TCP_FLG_ACK, /* 5, FIN 受信、クローズ待
147ち */
148 TCP_FLG_FIN | TCP_FLG_ACK, /* 6, 終了して、FIN 送信済み */
149 TCP_FLG_FIN | TCP_FLG_ACK, /* 7, 終了、FIN 交換済み、ACK 待
150ち */
151 TCP_FLG_FIN | TCP_FLG_ACK, /* 8, FIN 受信、終了、ACK 待
152ち */
153 TCP_FLG_ACK, /* 9, 終了、FIN 伝達確認受信、FIN待
154ち */
155 TCP_FLG_ACK, /* 10, 終了、時間待
156ち */
157 };
158
159/*
160 * send_segment -- TCP 出力処理
161 */
162
163static ER
164send_segment (bool_t *sendalot, T_TCP_CEP *cep, uint_t doff, uint_t win, uint_t len, uint8_t flags)
165{
166 T_NET_BUF *output;
167 T_TCP_HDR *tcph;
168 uint_t optlen, hdr_offset;
169 ER error;
170
171#ifdef TCP_CFG_OPT_MSS
172
173 uint8_t *optp;
174
175 if (flags & TCP_FLG_SYN)
176 optlen = TCP_OPT_LEN_MAXSEG;
177 else
178 optlen = 0;
179
180#else/* of #ifdef TCP_CFG_OPT_MSS */
181
182 optlen = 0;
183
184#endif/* of #ifdef TCP_CFG_OPT_MSS */
185
186 NET_COUNT_TCP(net_count_tcp[NC_TCP_SEND_SEGS], 1);
187 NET_COUNT_MIB(tcp_stats.tcpOutSegs, 1);
188
189 /*
190 * セグメント長を、相手の最大受信セグメント長に調整する。
191 * もし、超
192えている場合は、超
193えた分を後で送信する。
194 * このため、FIN ビットをクリアする。
195 *
196 * オリジナルでは、t_maxopd を制限長にしているが、
197 * 本実装
198では、相手の最大受信セグメントにする。
199 */
200 if (len + optlen > cep->maxseg) {
201 flags &= ~TCP_FLG_FIN;
202 len = cep->maxseg - optlen;
203 *sendalot = true;
204 }
205
206 /*
207 * 送信バッファが空になるときは PUSH フラグを設定する。
208 */
209 if (len && doff + len >= cep->swbuf_count)
210 flags |= TCP_FLG_PUSH;
211
212#if defined(TCP_CFG_SWBUF_CSAVE_ONLY)
213
214 if (len > 0 && ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_SEND_READY ||
215 (cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_SENT)) {
216
217 /*
218 * 送信ウインドバッファが開放されないようにして、
219 * ネットワークバッファを出力に移す。
220 */
221 cep->swbufq->flags |= NB_FLG_NOREL_IFOUT;
222 output = cep->swbufq;
223 }
224 else {
225
226 /*
227 * ACK 完了状æ…
228‹ã§ã€ã“の関数が呼び出されることもある。
229 * この時は、len を 0 にして、処理を継続する。
230 */
231 len = 0;
232 if ((error = tcpn_get_segment(&output, cep, optlen,
233 len, (uint_t)net_buf_max_siz(),
234 NBA_SEARCH_ASCENT, TMO_TCP_GET_NET_BUF)) != E_OK) {
235 if (cep->timer[TCP_TIM_REXMT] == 0)
236 cep->timer[TCP_TIM_REXMT] = cep->rxtcur;
237 goto err_ret;
238 }
239 }
240
241#elif defined(TCP_CFG_SWBUF_CSAVE) /* of #if defined(TCP_CFG_SWBUF_CSAVE_ONLY) */
242
243 if (IS_PTR_DEFINED(cep->sbuf)) {
244 if ((error = tcpn_get_segment(&output, cep, optlen,
245 len, (uint_t)net_buf_max_siz(),
246 NBA_SEARCH_ASCENT, TMO_TCP_GET_NET_BUF)) != E_OK) {
247 if (cep->timer[TCP_TIM_REXMT] == 0)
248 cep->timer[TCP_TIM_REXMT] = cep->rxtcur;
249 goto err_ret;
250 }
251 }
252 else if (len > 0 && ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_SEND_READY ||
253 (cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_SENT)) {
254
255 /*
256 * 送信ウインドバッファが開放されないようにして、
257 * ネットワークバッファを出力に移す。
258 */
259 cep->swbufq->flags |= NB_FLG_NOREL_IFOUT;
260 output = cep->swbufq;
261 }
262 else {
263
264 /*
265 * ACK 完了状æ…
266‹ã§ã€ã“の関数が呼び出されることもある。
267 * この時は、len を 0 にして、処理を継続する。
268 */
269 len = 0;
270 if ((error = tcpn_get_segment(&output, cep, optlen,
271 len, (uint_t)net_buf_max_siz(),
272 NBA_SEARCH_ASCENT, TMO_TCP_GET_NET_BUF)) != E_OK) {
273 if (cep->timer[TCP_TIM_REXMT] == 0)
274 cep->timer[TCP_TIM_REXMT] = cep->rxtcur;
275 goto err_ret;
276 }
277 }
278
279#else /* of #if defined(TCP_CFG_SWBUF_CSAVE_ONLY) */
280
281 if ((error = tcpn_get_segment(&output, cep, optlen,
282 len, (uint_t)net_buf_max_siz(),
283 NBA_SEARCH_ASCENT, TMO_TCP_GET_NET_BUF)) != E_OK) {
284 if (cep->timer[TCP_TIM_REXMT] == 0)
285 cep->timer[TCP_TIM_REXMT] = cep->rxtcur;
286 goto err_ret;
287 }
288
289#endif /* of #if defined(TCP_CFG_SWBUF_CSAVE_ONLY) */
290
291 /*
292 * TCP オプションの設定を行う。
293 * 本実装
294では、最大セグメントサイズのみ設定する。
295 */
296 hdr_offset = IF_IP_TCP_HDR_OFFSET(output);
297 if (flags & TCP_FLG_SYN) {
298 cep->snd_nxt = cep->iss;
299
300#ifdef TCP_CFG_OPT_MSS
301
302 optp = GET_TCP_OPT(output, hdr_offset);
303 *optp ++ = TCP_OPT_MAXSEG;
304 *optp ++ = TCP_OPT_LEN_MAXSEG;
305 *(uint16_t*)optp = htons(DEF_TCP_RCV_SEG);
306
307#endif/* of #ifdef TCP_CFG_OPT_MSS */
308
309 }
310
311 /* TCP SDU に送信データをコピーする。*/
312
313 if (len > 0) {
314 if (SEQ_LT(cep->snd_nxt, cep->snd_max)) {
315 NET_COUNT_TCP(net_count_tcp[NC_TCP_SEND_REXMIT_SEGS], 1);
316 NET_COUNT_MIB(tcp_stats.tcpRetransSegs, 1);
317 }
318 TCP_READ_SWBUF(cep, output, len, doff);
319 }
320 else {
321 if (cep->flags & TCP_CEP_FLG_ACK_NOW)
322 NET_COUNT_TCP(net_count_tcp[NC_TCP_SEND_ACKS], 1);
323 if (flags & (TCP_FLG_FIN | TCP_FLG_SYN | TCP_FLG_RST))
324 NET_COUNT_TCP(net_count_tcp[NC_TCP_SEND_CNTL_SEGS], 1);
325
326
327#ifdef TCP_CFG_EXTENTIONS
328
329 if (SEQ_LT(cep->snd_up, cep->snd_una))
330 NET_COUNT_TCP(net_count_tcp[NC_TCP_SEND_URG_SEGS], 1);
331
332#endif /* of #ifdef TCP_CFG_EXTENTIONS */
333
334 }
335
336 /*
337 * snd_max: 送信した最大 SEQ
338 * snd_nxt: 次に送信する SEQ
339 *
340 * 相手から FIN を受信し、まだ FIN を送信していないか、
341 * 送るデータがないときは、FIN を相手に届けるため、
342 * セグメントを送信するが、SEQ は進めない。
343 */
344 if ((flags & TCP_FLG_FIN) && (cep->flags & TCP_CEP_FLG_SENT_FIN) &&
345 cep->snd_nxt == cep->snd_max) {
346 cep->snd_nxt --;
347 }
348
349 tcph = GET_TCP_HDR(output, hdr_offset);
350
351 /*
352 * SEQ、ACK、フラグの設定。
353 */
354 if (len > 0 || (flags & (TCP_FLG_SYN | TCP_FLG_FIN)) || cep->timer[TCP_TIM_PERSIST] != 0)
355 tcph->seq = htonl(cep->snd_nxt);
356 else
357 tcph->seq = htonl(cep->snd_max);
358
359 /*
360 * rcv_nxt: 受信を期待
361している最小の SEQ
362 */
363 tcph->ack = htonl(cep->rcv_nxt);
364 tcph->flags = flags;
365
366 /*
367 * 受信ウィンドの計算
368 *
369 * rbufsz: 受信用バッファサイズ
370 * maxseg: 相手の最大受信セグメントサイズ
371 */
372 if (win < (cep->rbufsz / 4) && win < cep->maxseg)
373 win = 0;
374
375 /*
376 * rcv_nxt: 受信を期待
377している最小の SEQ
378 * rcv_adv: 受信を期待
379している最大の SEQ
380 */
381 if ((int32_t)win < (int32_t)(cep->rcv_adv - cep->rcv_nxt))
382 win = (uint_t)(cep->rcv_adv - cep->rcv_nxt);
383
384 tcph->win = htons(win);
385
386#ifdef TCP_CFG_EXTENTIONS
387
388 /*
389 * 緊急ポインタの設定
390 */
391 if (SEQ_GT(cep->snd_up, cep->snd_nxt)) {
392 if (TCP_CFG_URG_OFFSET)
393 tcph->urp = htons((uint16_t)(cep->snd_up - cep->snd_nxt));
394 else
395 tcph->urp = htons((uint16_t)(cep->snd_up - cep->snd_nxt - 1));
396 tcph->flags |= TCP_FLG_URG;
397 }
398 else
399 cep->snd_up = cep->snd_una;
400
401#endif /* of #ifdef TCP_CFG_EXTENTIONS */
402
403 /*
404 * チェックサムを設定する。
405 */
406 tcph->sum = 0;
407 tcph->sum = IN_CKSUM(output, IPPROTO_TCP, hdr_offset, GET_TCP_HDR_SIZE(output, hdr_offset) + len);
408
409 /* ネットワークバッファ長を調整する。*/
410 output->len = (uint16_t)(GET_IF_IP_TCP_HDR_SIZE(output, hdr_offset) + len);
411
412 /*
413 * タイマの調整
414 */
415 if ((cep->flags & TCP_CEP_FLG_FORCE) == 0 || cep->timer[TCP_TIM_PERSIST] == 0) {
416 T_TCP_SEQ startseq = cep->snd_nxt;
417
418 /*
419 * 次に送信する SEQ (snd_nxt) を今回送信するデータ数分進める。
420 */
421 if (flags & TCP_FLG_SYN)
422 cep->snd_nxt ++;
423 if (flags & TCP_FLG_FIN) {
424 cep->flags |= TCP_CEP_FLG_SENT_FIN;
425 cep->snd_nxt ++;
426 }
427
428 cep->snd_nxt += len;
429
430 /*
431 * 次に送信する SEQ (snd_nxt) が
432 * 送信した最大 SEQ (snd_max) より進んでいれば、
433 * 送信した最大 SEQ (snd_max) を更新する。
434 */
435 if (SEQ_GT(cep->snd_nxt, cep->snd_max)) {
436 cep->snd_max = cep->snd_nxt;
437 /*
438 * もし、往復時間計測を行っていなければ、
439 * この送信に時間を合わせる。
440 */
441 if (cep->rtt == 0) {
442 cep->rtt = 1;
443 cep->rtseq = startseq; /* 更新前の cep->snd_nxt */
444 }
445 }
446
447 /*
448 * もし設定されていないか、ACK または保留が発生していなければ、
449 * 再送タイマを設定する。設定する初期値は、
450 * 「滑らかな往復時間 + 2 × 往復時間変動」である。
451 * 再送時間のバックオフに使われるシフトカウントも初期化する。
452 */
453 if (cep->timer[TCP_TIM_REXMT] == 0 && cep->snd_nxt != cep->snd_una) {
454 cep->timer[TCP_TIM_REXMT] = cep->rxtcur;
455 if (cep->timer[TCP_TIM_PERSIST] != 0) {
456 cep->timer[TCP_TIM_PERSIST] = 0;
457 cep->rxtshift = 0;
458 }
459 }
460 }
461
462 /*
463 * 次に送信する SEQ (snd_nxt) + 今回送信するデータ数 (len) が
464 * 送信した最大 SEQ (snd_max) より進んでいれば、
465 * 送信した最大 SEQ (snd_max) を更新する。
466 */
467 else if (SEQ_GT(cep->snd_nxt + len, cep->snd_max))
468 cep->snd_max = cep->snd_nxt + len;
469
470#ifdef TCP_CFG_SWBUF_CSAVE
471
472 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_SEND_READY)
473 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_SENT;
474
475#endif /* of #ifdef TCP_CFG_SWBUF_CSAVE */
476
477#ifdef TCP_CFG_TRACE
478
479 tcp_output_trace(output, cep);
480
481#endif /* of #ifdef TCP_CFG_TRACE */
482
483 /* ネットワーク層 (IP) の出力関数を呼び出す。*/
484 if ((error = IP_OUTPUT(output, TMO_TCP_OUTPUT)) != E_OK)
485 goto err_ret;
486
487 /*
488 * 相手に伝えたウィンドウサイズ (win) が 0 以上で、
489 * 受信を期待
490している最小の SEQ (rcv_nxt) + win が
491 * 受信を期待
492している最大の SEQ (rcv_adv) より進んでいれば
493 * 受信を期待
494している最大の SEQ を更新する。
495 */
496 if (win > 0 && SEQ_GT(cep->rcv_nxt + win, cep->rcv_adv)) {
497 cep->rcv_adv = cep->rcv_nxt + win;
498 }
499
500 /*
501 * 最後に送信した ACK (last_ack_sent) を更新する。
502 */
503 cep->last_ack_sent = cep->rcv_nxt;
504
505 /*
506 * フラグの設定を行う。
507 */
508 cep->flags &= ~(TCP_CEP_FLG_ACK_NOW | TCP_CEP_FLG_DEL_ACK);
509 if (cep->flags & TCP_CEP_FLG_FORCE_CLEAR)
510 cep->flags &= ~(TCP_CEP_FLG_FORCE | TCP_CEP_FLG_FORCE_CLEAR);
511
512 return E_OK;
513
514err_ret:
515 /*
516 * 以下に関係しないフラグをクリアーする。
517 * ・送受信ウィンドバッファの省コピー機能
518 * ・動的な通信端点の生成・削除機能
519 */
520 cep->flags &= TCP_CEP_FLG_NOT_CLEAR;
521
522 return error;
523 }
524
525/*
526 * tcp_output -- TCP 出力処理
527 */
528
529void
530tcp_output (T_TCP_CEP *cep)
531{
532 bool_t sendalot = true, idle;
533 ER error = E_OK;
534 int32_t len;
535 uint_t doff, win;
536 uint8_t flags;
537
538 /*
539 * snd_una: 未確認の最小送信 SEQ または、確認された最大送信 SEQ
540 * snd_max: 送信した最大 SEQ
541 */
542 idle = (cep->snd_max == cep->snd_una);
543
544 /*
545 * idle: アイドル時間
546 * rxtcur: 現在の再送タイムアウト
547 */
548 if (idle && cep->idle >= cep->rxtcur)
549
550 /*
551 * snd_cwnd: 輻輳ウィンドサイズ
552 * maxseg : 相手の最大受信セグメントサイズ
553 *
554 * 長時間アイドルだったのでスロースタート制御に設定する。
555 */
556 cep->snd_cwnd = cep->maxseg;
557
558 while (error == E_OK && sendalot) {
559 sendalot = false;
560
561 /*
562 * snd_nxt: 次に送信する SEQ、この時点では、前回送信した SEQ
563 * snd_una: 未確認の最小送信 SEQ、または確認された最大送信 SEQ
564 *
565 * doff: 送信を開始するオフセット。
566 * swbuf_count (送信バッファにあるオクテット数)
567 * 0 V
568 * +-------------------------------------------+
569 * | sbuf |
570 * +-------------------------------------------+
571 * ^ ^
572 * |<------------->snd_nxt (前回送信した SEQ)
573 * | doff
574 * snd_una (まだ確認されていない)
575 */
576 doff = (uint_t)(cep->snd_nxt - cep->snd_una);
577
578 /*
579 * snd_wnd: 相手の受信可能ウィンドサイズ
580 * snd_cwnd: 輻輳ウィンドサイズ
581 *
582 * win: どちらか小さいウィンドサイズに設定する。
583 */
584 win = cep->snd_wnd < cep->snd_cwnd ? cep->snd_wnd : cep->snd_cwnd;
585
586 /* 出力フラグの設定 */
587 flags = tcp_outflags[cep->fsm_state];
588 if (cep->flags & TCP_CEP_FLG_NEED_FIN)
589 flags |= TCP_FLG_FIN;
590 if (cep->flags & TCP_CEP_FLG_NEED_SYN)
591 flags |= TCP_FLG_SYN;
592 if (cep->flags & TCP_CEP_FLG_FORCE) {
593
594 /*
595 * もし、送信ウインドサイズ (win) が 0 なら 1 オクテット送信する。
596 * そうでなければ、持続タイムアウトをキャンセルし、
597 * 再送信回数 (rxtshift) を 0 にする。
598 */
599 if (win == 0) {
600
601 /*
602 * doff: 送信するオクテット数。
603 * swbuf_count: 送信バッファの使用中サイズ
604 *
605 * 送信バッファに残っているオクテットが、これから
606 * 送信しようとしているオクテット数より多ければ
607 * FIN フラグをクリアする。
608 */
609 if (doff < cep->swbuf_count)
610 flags &=~TCP_FLG_FIN;
611 win = 1;
612 }
613 else {
614 /*
615 * TCP_TIM_PERSIST: 持続タイマ
616 * rxtshift: 再送信回数の log(2)
617 */
618 cep->timer[TCP_TIM_PERSIST] = 0;
619 cep->rxtshift = 0;
620 }
621 }
622
623 /*
624 * len: 今回送信するオクテット数
625 * swbuf_count (送信バッファにあるオクテット数)
626 * |
627 * 0 V
628 * +-------------------------------------------+
629 * | sbuf | |
630 * +-------------------------------------------+
631 * ^ ^<------------->
632 * | | len
633 * |<------------->snd_nxt (前回送信した SEQ)
634 * | doff
635 * snd_una (まだ確認されていない)
636 */
637 if (cep->swbuf_count < win)
638 len = (int32_t)cep->swbuf_count - doff;
639 else
640 len = (int32_t)win - doff;
641
642 /*
643 * すでに送信されていれば、SYN ビットをオフする。
644 * しかし、以下の条件では送信を控える。
645 *
646 * ・状æ…
647‹ãŒ SYN 送信。
648 * ・セグメントがデータを含んでいる。
649 */
650 if ((flags & TCP_FLG_SYN) && SEQ_GT(cep->snd_nxt, cep->snd_una)) {
651 flags &= ~TCP_FLG_SYN;
652 doff --; /* -1 は SYN フラグ分 */
653 len ++; /* +1 は SYN フラグ分 */
654 if (len > 0 && cep->fsm_state == TCP_FSM_SYN_SENT)
655 break;
656 }
657
658 if (flags & TCP_FLG_SYN) {
659 len = 0;
660 flags &= ~TCP_FLG_FIN;
661 }
662
663 if (len < 0) {
664
665 /*
666 * len が 0 以下なら、0 に設定する。
667 * もし、送信ウィンドウサイズが 0 なら、
668 * 再送信タイマをキャンセルし、
669 * 前回送信した SEQ (snd_nxt) を
670 * 確認された最大送信 SEQ (snd_una) に戻す。
671 * そして、持続タイマーが止まっていれば、再設定する。
672 */
673 len = 0;
674 if (win == 0) {
675 cep->timer[TCP_TIM_REXMT] = 0;
676 cep->rxtshift = 0;
677 cep->snd_nxt = cep->snd_una;
678 if (cep->timer[TCP_TIM_PERSIST] == 0)
679 tcp_set_persist_timer(cep);
680 }
681 }
682
683
684 /*
685 * 今回送信するオクテット数 (len) は、
686 * 相手の最大受信セグメントサイズ (maxseg) を超
687えないようにする。
688 */
689 if (len > cep->maxseg) {
690 len = cep->maxseg;
691 sendalot = true;
692 }
693
694 /*
695 * swbuf_count (送信バッファにあるオクテット数)
696 * |
697 * 0 V
698 * +-------------------------------------------+
699 * | sbuf | |
700 * +-------------------------------------------+
701 * ^ ^<------------->
702 * | | len
703 * |<------------->snd_nxt (前回送信した SEQ)
704 * | doff
705 * snd_una (まだ確認されていない)
706 *
707 * 今回送信後も、送信バッファにデータが残っていれば
708 * FIN フラグをクリアする。
709 */
710 if (SEQ_LT(cep->snd_nxt + len, cep->snd_una + cep->swbuf_count))
711 flags &= ~TCP_FLG_FIN;
712
713 /*
714 * ここから win は、受信ウィンドウサイズ。
715 * 受信バッファの空き容量
716 */
717 win = cep->rbufsz - cep->rwbuf_count;
718
719 /*
720 * 愚かなウィンドウ・シンドロームの回避処理 (送信側)
721 *
722 * 以下の条件で、送信を行う。
723 *
724 * ・フルサイズ (maxseg) のセグメントを送ることができる。
725 * ・相手の最大の受信ウィンドウサイズの 1/2 のデータを
726 * 送ることができる。
727 * ・送信バッファを空にでき、アイドルか非遅
728延オプションが有効なとき。
729 */
730 if (len) {
731
732 /*
733 * 今回送信するオクテット数 (len) が
734 * 相手の最大受信セグメントサイズ (maxseg) に
735 * 一致するときは送信する。
736 */
737 if (len == cep->maxseg) {
738 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
739 continue;
740 }
741
742 /*
743 * 今回の送信で、送信バッファを空にでき、
744 * アイドルか非 PUSH オプションが有効なとき。
745 */
746 if ((idle || (cep->flags & TCP_CEP_FLG_NO_DELAY)) &&
747 (cep->flags & TCP_CEP_FLG_NO_PUSH) == 0 &&
748 len + doff >= cep->swbuf_count) {
749 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
750 continue;
751 }
752
753 /*
754 * max_sndwnd: 今までの最大送信ウィンドサイズ
755 * snd_nxt: 次に送信する SEQ
756 * snd_max: 送信した最大 SEQ
757 *
758 * 次の条件では送信を行う。
759 *
760 * ・強制送信フラグがセットされている。
761 * ・データ長が相手の最大の受信ウィンドウサイズの 1/2 以上で、
762 * 相手の最大の受信ウィンドウサイズが 0 より大きい。
763 * ・次に送信する SEQ が送信した最大 SEQ より小さい、
764 * つまり、再送するとき。
765 */
766 if ((cep->flags & TCP_CEP_FLG_FORCE) ||
767 (len >= cep->max_sndwnd / 2 && cep->max_sndwnd > 0) ||
768 SEQ_LT(cep->snd_nxt, cep->snd_max)) {
769 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
770 continue;
771 }
772 }
773
774
775 /*
776 * 愚かなウィンドウ・シンドロームの回避処理 (受信側)
777 *
778 * ウィンドウサイズがフルサイズの 2 倍のセグメント、あるいは
779 * 受信バッファ容量の 1/2 の、いずれか小さいほうの
780 * サイズで増加される場合は、ウィンドウサイズの更新を行う。
781 */
782 if (win > 0) {
783 long adv;
784
785 /*
786 * win: 受信バッファの空き容量
787 * MAX_TCP_WIN_SIZE: TCP ヘッダの win フィールドに設定できる最大値
788 * rcv_adv: 受信を期待
789している最大の SEQ
790 * rcv_nxt: 受信を期待
791している最小の SEQ
792 */
793 if (win < MAX_TCP_WIN_SIZE)
794 adv = win - (cep->rcv_adv - cep->rcv_nxt);
795 else
796 adv = MAX_TCP_WIN_SIZE - (cep->rcv_adv - cep->rcv_nxt);
797
798 if (adv >= (long)(cep->maxseg * 2) ||
799 adv * 2 >= (long) cep->rbufsz) {
800 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
801 continue;
802 }
803 }
804
805 /*
806 * ACK を送信する。
807 */
808 if (cep->flags & TCP_CEP_FLG_ACK_NOW) {
809 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
810 continue;
811 }
812
813 if ( (flags & TCP_FLG_RST) ||
814 ((flags & TCP_FLG_SYN) && (cep->flags & TCP_CEP_FLG_NEED_SYN) == 0)) {
815 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
816 continue;
817 }
818
819#ifdef TCP_CFG_EXTENTIONS
820
821 if (SEQ_GT(cep->snd_up, cep->snd_una)) {
822 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
823 continue;
824 }
825
826#endif /* of #ifdef TCP_CFG_EXTENTIONS */
827
828 /*
829 * snd_nxt: 次に送信する SEQ
830 * snd_una: 未確認の最小送信 SEQ、または確認された最大送信 SEQ
831 *
832 * 相手から FIN を受信し、まだ FIN を送信していないか、
833 * 送るデータがないときは、FIN を相手に届けるため、
834 * セグメントを送信する。
835 */
836 if ((flags & TCP_FLG_FIN) &&
837 ((cep->flags & TCP_CEP_FLG_SENT_FIN) == 0 || cep->snd_nxt == cep->snd_una)) {
838 error = send_segment(&sendalot, cep, doff, win, (uint_t)len, flags);
839 continue;
840 }
841
842 /*
843 * 送信すべきデータがあり、再送タイマと持続タイマが切れているときは
844 * 持続タイマを設定する。
845 */
846 if (cep->swbuf_count && cep->timer[TCP_TIM_REXMT ] == 0 &&
847 cep->timer[TCP_TIM_PERSIST] == 0) {
848 cep->rxtshift = 0;
849 tcp_set_persist_timer(cep);
850 break;
851 }
852
853 }
854 }
855
856#ifdef TCP_CFG_SWBUF_CSAVE
857
858/*
859 * tcptsk_alloc_swbufq -- 送信ウィンドバッファ割り当て
860 */
861
862static void
863tcptsk_alloc_swbufq (T_TCP_CEP *cep)
864{
865 ER error;
866 uint_t win;
867
868 /*
869 * snd_wnd: 相手の受信可能ウィンドサイズ
870 * snd_cwnd: 輻輳ウィンドサイズ
871 *
872 * win: どちらか小さいウィンドサイズに設定する。
873 */
874 win = cep->snd_wnd < cep->snd_cwnd ? cep->snd_wnd : cep->snd_cwnd;
875
876 /*
877 * 相手の受信ウィンドが閉じている場合は、開くまで待
878機する。
879 */
880 if (win == 0) {
881 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_WOPEN_PEND;
882 }
883 else {
884
885#ifdef TCP_CFG_NON_BLOCKING
886
887 /* ノンブロッキングコール */
888 if (!IS_PTR_DEFINED(cep->callback)) {
889 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
890
891 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
892 cep->snd_tskid = TA_NULL;
893 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
894 return;
895 }
896
897#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
898
899 if ((error = tcpn_get_segment(&cep->swbufq, cep, 0,
900 (uint_t)TCP_CFG_SWBUF_CSAVE_MIN_SIZE,
901 (uint_t)TCP_CFG_SWBUF_CSAVE_MAX_SIZE,
902 (ATR)(NBA_SEARCH_DESCENT |
903 NBA_RESERVE_TCP |
904 (GET_TCP_CEPID(cep) & NBA_ID_MASK)), TMO_POL)) != E_OK) {
905
906 /* ネットワークバッファを予約する。*/
907 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_NBUF_PEND;
908 }
909 else {
910
911 /* 送信ウィンドバッファを初期化する。*/
912 tcp_init_swbuf(cep);
913
914#ifdef TCP_CFG_NON_BLOCKING
915
916 if (cep->snd_nblk_tfn == TFN_TCP_GET_BUF) {
917
918 uint_t len;
919
920 /* 送信ウィンドバッファの書き込みアドレスを設定する。*/
921 len = TCP_GET_SWBUF_ADDR(cep, cep->snd_p_buf);
922
923 /* コールバック関数を呼び出す。*/
924#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
925 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)(uint32_t)len);
926#else
927 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)&len);
928#endif
929
930
931 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
932 cep->snd_tskid = TA_NULL;
933 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
934 }
935
936 else { /* cep->snd_nblk_tfn == TFN_TCP_SND_DAT || */
937 /* cep->snd_nblk_tfn == TFN_TCP_SND_OOB */
938
939 uint_t len;
940
941 /* 送信ウィンドバッファにデータを書き込む。*/
942 len = TCP_WRITE_SWBUF(cep, cep->snd_data, (uint_t)cep->snd_len);
943
944#ifdef TCP_CFG_EXTENTIONS
945
946 /* 送信緊急ポインタを設定する。*/
947 if (cep->snd_nblk_tfn == TFN_TCP_SND_OOB)
948 cep->snd_up = cep->snd_una + len;
949
950#endif /* of #ifdef TCP_CFG_EXTENTIONS */
951
952 /* フラグを、送信可能に設定し、強制的に送信する。*/
953 cep->flags |= TCP_CEP_FLG_FORCE | TCP_CEP_FLG_FORCE_CLEAR | TCP_CEP_FLG_POST_OUTPUT;
954
955 /* コールバック関数を呼び出す。*/
956#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
957 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)(uint32_t)len);
958#else
959 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)&len);
960#endif
961
962
963 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
964 cep->snd_tskid = TA_NULL;
965 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
966 }
967
968#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
969
970 }
971 }
972 }
973
974/*
975 * tcptsk_free_swbufq -- 送信ウィンドバッファ開放
976 */
977
978static void
979tcptsk_free_swbufq (T_TCP_CEP *cep)
980{
981 /*
982 * 受信確認が完了し、ネットワークインタフェースからの
983 * 出力も完了したときは、送信ウィンドバッファキューを解放する。
984 */
985
986 /* 送信ウィンドバッファの使用中サイズをリセットする。*/
987 cep->swbuf_count = 0;
988
989 /* 送信ウィンドバッファキューのネットワークバッファを解放する。*/
990 syscall(rel_net_buf(cep->swbufq));
991 cep->swbufq = NULL;
992
993 /* フラグを空きに設定する。*/
994 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_FREE;
995
996 /* 送信ウィンドバッファに空きができたことを知らせる。*/
997 syscall(set_flg(cep->snd_flgid, TCP_CEP_EVT_SWBUF_READY));
998
999 /* 送信ウィンドバッファの空き待
1000ちのときは、TCP 出力タスクを起動する。*/
1001 if ((cep->flags & TCP_CEP_FLG_WBCS_NBUF_REQ) != 0) {
1002 sig_sem(SEM_TCP_POST_OUTPUT);
1003 }
1004 }
1005
1006#endif /* of #ifdef TCP_CFG_SWBUF_CSAVE */
1007
1008/*
1009 * TCP 出力タスク
1010 */
1011
1012void
1013tcp_output_task (intptr_t exinf)
1014{
1015 static int_t last_ix = 0;
1016
1017 T_TCP_CEP *cep;
1018 ID tskid;
1019 int_t ix, sel_ix;
1020
1021 get_tid(&tskid);
1022 syslog(LOG_NOTICE, "[TCP OUTPUT:%d] started.", tskid);
1023
1024 tcp_init();
1025
1026#ifdef _IP6_CFG
1027
1028 /* IPv6 のステートレス・アドレス自動設定を実行する。*/
1029 in6_if_up(IF_GET_IFNET());
1030
1031#endif /* of #ifdef _IP6_CFG */
1032
1033 while (true) {
1034
1035 /* 出力がポストされるまで待
1036つ。*/
1037 syscall(wai_sem(SEM_TCP_POST_OUTPUT));
1038
1039 if (++ last_ix == tmax_tcp_cepid)
1040 last_ix = 0;
1041 sel_ix = ix = last_ix;
1042 do {
1043 cep = &tcp_cep[ix];
1044
1045#ifdef TCP_CFG_SWBUF_CSAVE
1046
1047 if ((cep->flags & TCP_CEP_FLG_WBCS_NBUF_REQ) != 0 &&
1048 ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_FREE ||
1049 (cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_NBUF_RSVD)) {
1050 tcptsk_alloc_swbufq(cep);
1051 sel_ix = ix;
1052 }
1053
1054 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_ACKED &&
1055 (cep->swbufq->flags & NB_FLG_NOREL_IFOUT) == 0) {
1056 tcptsk_free_swbufq(cep);
1057 sel_ix = ix;
1058 }
1059
1060 /*
1061 * ネットワークインタフェースから送信が終わっていないときは、
1062 * 送信を予約する。
1063 */
1064 if (cep->flags & TCP_CEP_FLG_POST_OUTPUT &&
1065 (cep->flags & TCP_CEP_FLG_WBCS_MASK) >= TCP_CEP_FLG_WBCS_SENT) {
1066 syscall(wai_sem(cep->semid_lock));
1067 if (cep->swbufq == NULL)
1068 cep->flags &= ~TCP_CEP_FLG_POST_OUTPUT;
1069 else if (cep->swbufq->flags & NB_FLG_NOREL_IFOUT) {
1070 cep->flags &= ~TCP_CEP_FLG_POST_OUTPUT;
1071 cep->flags |= TCP_CEP_FLG_RESERVE_OUTPUT;
1072 }
1073 syscall(sig_sem(cep->semid_lock));
1074 }
1075
1076 /*
1077 * 送信予約中に、ネットワークインタフェースから送信が終了したら、
1078 * 送信を開始する。ただし、完å…
1079¨ã«é€ä¿¡ãŒçµ‚了したときは何もしない。
1080 */
1081 if (cep->flags & TCP_CEP_FLG_RESERVE_OUTPUT) {
1082 syscall(wai_sem(cep->semid_lock));
1083 if (cep->swbufq != NULL && (cep->swbufq->flags & NB_FLG_NOREL_IFOUT) == 0) {
1084 cep->flags |= TCP_CEP_FLG_POST_OUTPUT;
1085 }
1086 syscall(sig_sem(cep->semid_lock));
1087 cep->flags &= ~TCP_CEP_FLG_RESERVE_OUTPUT;
1088 }
1089
1090#endif /* of #ifdef TCP_CFG_SWBUF_CSAVE */
1091
1092 if (cep->flags & TCP_CEP_FLG_POST_OUTPUT) {
1093
1094 cep->flags &= ~TCP_CEP_FLG_POST_OUTPUT;
1095
1096#ifdef TCP_CFG_NON_BLOCKING
1097
1098 if (cep->snd_nblk_tfn == TFN_TCP_CON_CEP && cep->myaddr.portno == TCP_PORTANY) {
1099 ER error;
1100
1101 /*
1102 * tcp_con_cep のノンブロッキングコールで、
1103 * 未割当のの場合は、ポート番号を割り当てる。
1104 * p_myaddr が NADR (-1) か、
1105 * 自ポート番号が TCP_PORTANY なら、自動で割り当てる。
1106 */
1107 if (cep->p_myaddr == NADR || cep->p_myaddr->portno == TCP_PORTANY)
1108 tcp_alloc_auto_port(cep);
1109 else if ((error = tcp_alloc_port(cep, cep->p_myaddr->portno)) != E_OK) {
1110
1111 if (IS_PTR_DEFINED(cep->callback))
1112#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
1113 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)error);
1114#else
1115 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)&error);
1116#endif
1117 else
1118 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
1119
1120 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
1121 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
1122 cep->snd_tskid = TA_NULL;
1123 continue;
1124 }
1125 }
1126
1127#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
1128
1129 tcp_output(cep);
1130
1131 if (cep->flags & TCP_CEP_FLG_CLOSE_AFTER_OUTPUT) {
1132 /* コネクションを閉じる。*/
1133 tcp_close(cep);
1134 cep->flags &= ~TCP_CEP_FLG_CLOSE_AFTER_OUTPUT;
1135 }
1136
1137 if (cep->flags & TCP_CEP_FLG_RESTORE_NEXT_OUTPUT) {
1138 /* snd_nxt をå…
1139ƒã«æˆ»ã™ã€‚*/
1140 if (SEQ_GT(cep->snd_old_nxt, cep->snd_nxt))
1141 cep->snd_nxt = cep->snd_old_nxt;
1142 cep->flags &= ~TCP_CEP_FLG_RESTORE_NEXT_OUTPUT;
1143 }
1144
1145 sel_ix = ix;
1146 }
1147
1148 if (++ ix == tmax_tcp_cepid)
1149 ix = 0;
1150 } while (ix != last_ix);
1151
1152 /* 次回は、処理した通信端点を後回しにする。*/
1153 last_ix = sel_ix;
1154 }
1155 }
1156
1157#endif /* of #ifdef SUPPORT_TCP */
Note: See TracBrowser for help on using the repository browser.