source: EcnlProtoTool/trunk/asp3_dcre/tinet/netinet/tcp_subr.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: 45.2 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_subr.c 270 2017-02-09 04:03:47Z 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_subr.c 8.2 (Berkeley) 5/24/95
79 * $FreeBSD: src/sys/netinet/tcp_subr.c,v 1.49.2.4 1999/08/29 16:29:55 peter Exp $
80 */
81
82#include <stdarg.h>
83#include <string.h>
84
85#ifdef TARGET_KERNEL_ASP
86
87#include <kernel.h>
88#include <sil.h>
89#include <syssvc/serial.h>
90#include <t_syslog.h>
91#include "kernel_cfg.h"
92
93#endif /* of #ifdef TARGET_KERNEL_ASP */
94
95#ifdef TARGET_KERNEL_JSP
96
97#include <s_services.h>
98#include <t_services.h>
99#include "kernel_id.h"
100
101#endif /* of #ifdef TARGET_KERNEL_JSP */
102
103#include <tinet_defs.h>
104#include <tinet_config.h>
105
106#include <net/if.h>
107#include <net/if_ppp.h>
108#include <net/if_loop.h>
109#include <net/ethernet.h>
110#include <net/if_arp.h>
111#include <net/ppp_ipcp.h>
112#include <net/net.h>
113#include <net/net_var.h>
114#include <net/net_buf.h>
115#include <net/net_timer.h>
116#include <net/net_count.h>
117
118#include <netinet/in.h>
119#include <netinet6/in6.h>
120#include <netinet6/in6_var.h>
121#include <netinet/in_var.h>
122#include <netinet/ip.h>
123#include <netinet/ip_var.h>
124#include <netinet/ip6.h>
125#include <netinet6/ip6_var.h>
126#include <netinet6/nd6.h>
127#include <netinet/tcp.h>
128#include <netinet/tcp_timer.h>
129#include <netinet/tcp_var.h>
130#include <netinet/tcp_fsm.h>
131#include <netinet/tcp_seq.h>
132#include <netinet/in_itron.h>
133
134#ifdef SUPPORT_TCP
135
136/*
137 * å…
138¨åŸŸå¤‰æ•°
139 */
140
141/*
142 * TCP の SEQ の初期値、プログラムが起動して、最初に TCP セグメントを
143 * 送受信するときに、get_tim() により初期化する。
144 */
145T_TCP_SEQ tcp_iss = 0;
146
147#ifdef SUPPORT_MIB
148
149/*
150 * SNMP の 管理情
151報ベース (MIB)
152 */
153
154T_TCP_STATS tcp_stats;
155
156#endif /* of #ifdef SUPPORT_MIB */
157
158/*
159 * 局所変数
160 */
161
162static uint16_t tcp_port_auto = TCP_PORT_FIRST_AUTO; /* 自動割り当て番号 */
163
164/*
165 * tcp_free_reassq -- 受信再構成キューのネットワークバッファを解放する。
166 *
167 * 注意:
168 * 必
169要であれば、この関数を呼び出す前に、通信端点をロックし、
170 * 戻った後、解除する必
171要がある。
172 */
173
174void
175tcp_free_reassq (T_TCP_CEP *cep)
176{
177 T_NET_BUF *q, *nq;
178
179 for (q = cep->reassq; q != NULL; q = nq) {
180 nq = GET_TCP_Q_HDR(q, GET_TCP_IP_Q_HDR(q)->thoff)->next;
181 syscall(rel_net_buf(q));
182 }
183 cep->reassq = NULL;
184 NET_COUNT_TCP(net_count_tcp[NC_TCP_FREE_RCV_QUEUE], 1);
185 }
186
187/*
188 * tcp_alloc_auto_port -- 自動割り当てポート番号を設定する。
189 */
190
191void
192tcp_alloc_auto_port (T_TCP_CEP *cep)
193{
194 int_t ix;
195 uint16_t portno;
196
197 while (true) {
198 portno = tcp_port_auto ++;
199 if (tcp_port_auto > TCP_PORT_LAST_AUTO)
200 tcp_port_auto = TCP_PORT_FIRST_AUTO;
201
202#ifdef TCP_CFG_PASSIVE_OPEN
203
204 for (ix = tmax_tcp_repid; ix -- > 0; ) {
205
206#ifdef TCP_CFG_EXTENTIONS
207
208 if (VALID_TCP_REP(&tcp_rep[ix]) && tcp_rep[ix].myaddr.portno == portno) {
209 portno = TCP_PORTANY;
210 break;
211 }
212
213#else /* of #ifdef TCP_CFG_EXTENTIONS */
214
215 if (tcp_rep[ix].myaddr.portno == portno) {
216 portno = TCP_PORTANY;
217 break;
218 }
219
220#endif /* of #ifdef TCP_CFG_EXTENTIONS */
221
222 }
223
224#endif /* of #ifdef TCP_CFG_PASSIVE_OPEN */
225
226 if (portno != TCP_PORTANY) {
227
228 syscall(wai_sem(SEM_TCP_CEP));
229 for (ix = tmax_tcp_cepid; ix -- > 0; ) {
230 if (VALID_TCP_CEP(&tcp_cep[ix]) && tcp_cep[ix].myaddr.portno == portno) {
231 portno = TCP_PORTANY;
232 break;
233 }
234 }
235
236 if (portno != TCP_PORTANY) {
237 cep->myaddr.portno = portno;
238 syscall(sig_sem(SEM_TCP_CEP));
239 return;
240 }
241 syscall(sig_sem(SEM_TCP_CEP));
242 }
243 }
244 }
245
246/*
247 * tcp_alloc_port -- 指定されたポート番号を設定する。
248 */
249
250ER
251tcp_alloc_port (T_TCP_CEP *cep, uint16_t portno)
252{
253 int_t ix;
254
255 syscall(wai_sem(SEM_TCP_CEP));
256 for (ix = tmax_tcp_cepid; ix -- > 0; )
257 if (VALID_TCP_CEP(cep) && tcp_cep[ix].myaddr.portno == portno) {
258 syscall(sig_sem(SEM_TCP_CEP));
259 return E_PAR;
260 }
261 cep->myaddr.portno = portno;
262 syscall(sig_sem(SEM_TCP_CEP));
263 return E_OK;
264 }
265
266/*
267 * tcp_init -- TCP モジュールの初期化
268 */
269
270void
271tcp_init (void)
272{
273 timeout(tcp_slow_timo, NULL, TCP_SLOW_TMO);
274
275#ifdef TCP_CFG_DELAY_ACK
276
277 timeout(tcp_fast_timo, NULL, TCP_FAST_TMO);
278
279#endif/* of #ifdef TCP_CFG_DELAY_ACK */
280 }
281
282/*
283 * tcp_init_iss シーケンス番号を初期化する。
284 */
285
286void
287tcp_init_iss (void)
288{
289 SYSTIM now;
290
291#ifdef SUPPORT_ETHER
292
293 T_IF_SOFTC *ic;
294
295 ic = IF_ETHER_NIC_GET_SOFTC();
296 syscall(get_tim(&now));
297 net_srand(now + (ic->ifaddr.lladdr[2] << 24)
298 + (ic->ifaddr.lladdr[3] << 16)
299 + (ic->ifaddr.lladdr[4] << 8)
300 + (ic->ifaddr.lladdr[5] ));
301
302#else /* of #ifdef SUPPORT_ETHER */
303
304 syscall(get_tim(&now));
305 net_srand(now);
306
307#endif /* of #ifdef SUPPORT_ETHER */
308
309 tcp_iss = net_rand();
310 }
311
312/*
313 * tcp_close -- コネクションを開放する。
314 */
315
316T_TCP_CEP *
317tcp_close (T_TCP_CEP *cep)
318{
319 /* タイマーを停止する。*/
320 tcp_cancel_timers(cep);
321
322 /*
323 * 通信端点をロックし、
324 * 受信再構成キューのネットワークバッファを解放する。
325 */
326 syscall(wai_sem(cep->semid_lock));
327 tcp_free_reassq(cep);
328 syscall(sig_sem(cep->semid_lock));
329
330 /* 状æ…
331‹ã‚’未使用にする。*/
332 cep->fsm_state = TCP_FSM_CLOSED;
333
334 /*
335 * 以下に関係しないフラグをクリアーする。
336 * ・送受信ウィンドバッファの省コピー機能
337 * ・動的な通信端点の生成・削除機能
338 */
339 cep->flags &= (TCP_CEP_FLG_WBCS_NBUF_REQ | TCP_CEP_FLG_WBCS_MASK |
340 TCP_CEP_FLG_DYNAMIC | TCP_CEP_FLG_VALID);
341
342#ifdef TCP_CFG_NON_BLOCKING
343
344 if (cep->snd_nblk_tfn != TFN_TCP_UNDEF || cep->rcv_nblk_tfn != TFN_TCP_UNDEF) {
345 /* ノンブロッキングコール */
346
347#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
348
349 if (!IS_PTR_DEFINED(cep->callback))
350 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
351 else {
352 if (cep->rcv_nblk_tfn != TFN_TCP_UNDEF) {
353 ER_UINT len;
354
355 switch (cep->rcv_nblk_tfn) {
356
357 case TFN_TCP_ACP_CEP:
358 /* TCP 通信端点からTCP 受付口を解放する。*/
359 cep->rep = NULL;
360 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)E_CLS);
361 break;
362
363 case TFN_TCP_RCV_BUF:
364
365 /* 受信ウィンドバッファの空アドレスを獲得する。*/
366 len = TCP_GET_RWBUF_ADDR(cep, cep->rcv_p_buf);
367
368 /* 異常切断等のエラーを設定する。*/
369 if (cep->error == E_TMOUT)
370 len = E_CLS;
371 else if (cep->error < 0)
372 len = cep->error;
373
374 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)(uint32_t)len);
375 break;
376
377 case TFN_TCP_RCV_DAT:
378
379 /* 受信ウィンドバッファからデータを取り出す。*/
380 len = TCP_READ_RWBUF(cep, cep->rcv_data, (uint_t)cep->rcv_len);
381
382 /* 異常切断等のエラーを設定する。*/
383 if (cep->error == E_TMOUT)
384 len = E_CLS;
385 else if (cep->error != E_OK)
386 len = cep->error;
387
388 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)(uint32_t)len);
389 break;
390
391 case TFN_TCP_CLS_CEP:
392
393 if (cep->error == E_TMOUT)
394 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)E_CLS);
395 else
396 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)cep->error);
397 break;
398
399 default:
400 syslog(LOG_WARNING, "[TCP] unexp TFN: %s.", in_strtfn((FN)cep->rcv_nblk_tfn));
401 break;
402 }
403
404 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
405 cep->rcv_tskid = TA_NULL;
406 cep->rcv_tfn = cep->rcv_nblk_tfn = TFN_TCP_UNDEF;
407 }
408
409 if (cep->snd_nblk_tfn != TFN_TCP_UNDEF) {
410
411 switch (cep->snd_nblk_tfn) {
412
413 case TFN_TCP_CON_CEP:
414 /* TCP 通信端点から TCP 受付口を解放する。*/
415 cep->rep = NULL;
416 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)E_CLS);
417 break;
418
419 case TFN_TCP_SND_DAT:
420 case TFN_TCP_GET_BUF:
421 if (cep->error == E_TMOUT)
422 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)E_CLS);
423 else
424 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)cep->error);
425 break;
426
427 default:
428 syslog(LOG_WARNING, "[TCP] unexp TFN: %s.", in_strtfn((FN)cep->snd_nblk_tfn));
429 break;
430 }
431
432 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
433 cep->snd_tskid = TA_NULL;
434 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
435 }
436
437 }
438
439#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
440
441 if (!IS_PTR_DEFINED(cep->callback))
442 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
443 else {
444 if (cep->rcv_nblk_tfn != TFN_TCP_UNDEF) {
445 ER_UINT len;
446
447 switch (cep->rcv_nblk_tfn) {
448
449 case TFN_TCP_ACP_CEP:
450 /* TCP 通信端点からTCP 受付口を解放する。*/
451 cep->rep = NULL;
452 len = E_CLS;
453 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&len);
454 break;
455
456 case TFN_TCP_RCV_BUF:
457
458 /* 受信ウィンドバッファの空アドレスを獲得する。*/
459 len = TCP_GET_RWBUF_ADDR(cep, cep->rcv_p_buf);
460
461 /* 異常切断等のエラーを設定する。*/
462 if (cep->error == E_TMOUT)
463 len = E_CLS;
464 else if (cep->error < 0)
465 len = cep->error;
466
467 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&len);
468 break;
469
470 case TFN_TCP_RCV_DAT:
471
472 /* 受信ウィンドバッファからデータを取り出す。*/
473 len = TCP_READ_RWBUF(cep, cep->rcv_data, (uint_t)cep->rcv_len);
474
475 /* 異常切断等のエラーを設定する。*/
476 if (cep->error == E_TMOUT)
477 len = E_CLS;
478 else if (cep->error != E_OK)
479 len = cep->error;
480
481 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&len);
482 break;
483
484 case TFN_TCP_CLS_CEP:
485 if (cep->error == E_TMOUT)
486 len = E_CLS;
487 else
488 len = cep->error;
489 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&len);
490 break;
491
492 default:
493 syslog(LOG_WARNING, "[TCP] unexp TFN: %s.", in_strtfn((FN)cep->rcv_nblk_tfn));
494 break;
495 }
496
497 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
498 cep->rcv_tskid = TA_NULL;
499 cep->rcv_tfn = cep->rcv_nblk_tfn = TFN_TCP_UNDEF;
500 }
501
502 if (cep->snd_nblk_tfn != TFN_TCP_UNDEF) {
503 ER_UINT len;
504
505 switch (cep->snd_nblk_tfn) {
506
507 case TFN_TCP_CON_CEP:
508 /* TCP 通信端点から TCP 受付口を解放する。*/
509 cep->rep = NULL;
510 len = E_CLS;
511 (*cep->callback)(GET_TCP_CEPID(cep), cep->snd_nblk_tfn, (void*)&len);
512 break;
513
514 case TFN_TCP_SND_DAT:
515 case TFN_TCP_GET_BUF:
516 if (cep->error == E_TMOUT)
517 len = E_CLS;
518 else
519 len = cep->error;
520 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&len);
521 break;
522
523 default:
524 syslog(LOG_WARNING, "[TCP] unexp TFN: %s.", in_strtfn((FN)cep->snd_nblk_tfn));
525 break;
526 }
527
528 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
529 cep->snd_tskid = TA_NULL;
530 cep->snd_tfn = cep->snd_nblk_tfn = TFN_TCP_UNDEF;
531 }
532
533 }
534
535#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
536
537 /*
538 * 通信端点をロックし、
539 * 送受信ウィンドバッファキューのネットワークバッファを解放する。
540 */
541 syscall(wai_sem(cep->semid_lock));
542 TCP_FREE_RWBUFQ(cep);
543 TCP_FREE_SWBUFQ(cep);
544 syscall(sig_sem(cep->semid_lock));
545
546 /* 未使用になったことを知らせる。*/
547 syscall(set_flg(cep->est_flgid, TCP_CEP_EVT_CLOSED));
548 }
549 else { /* 非ノンブロッキングコール */
550
551#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
552
553 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
554 cep->snd_tskid = cep->rcv_tskid = TA_NULL;
555 cep->snd_tfn = cep->rcv_tfn = TFN_TCP_UNDEF;
556
557 /*
558 * 通信端点をロックし、
559 * 送受信ウィンドバッファキューのネットワークバッファを解放する。
560 */
561 syscall(wai_sem(cep->semid_lock));
562 TCP_FREE_RWBUFQ(cep);
563 TCP_FREE_SWBUFQ(cep);
564 syscall(sig_sem(cep->semid_lock));
565
566 /* 未使用になったことを知らせる。*/
567 syscall(set_flg(cep->est_flgid, TCP_CEP_EVT_CLOSED));
568
569 /*
570 * å…
571¥å‡ºåŠ›ã‚¿ã‚¹ã‚¯ã‚’起床して、
572 * 送受信不可になったことを知らせる。
573 */
574 syscall(set_flg(cep->snd_flgid, TCP_CEP_EVT_SWBUF_READY));
575 syscall(set_flg(cep->rcv_flgid, TCP_CEP_EVT_RWBUF_READY));
576
577#ifdef TCP_CFG_NON_BLOCKING
578
579 }
580
581#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
582
583 return NULL;
584 }
585
586/*
587 * tcp_drop -- TCP 接続を破棄する。
588 */
589
590T_TCP_CEP *
591tcp_drop (T_TCP_CEP *cep, ER errno)
592{
593#ifdef SUPPORT_MIB
594
595 if ((cep->fsm_state == TCP_FSM_SYN_SENT) || (cep->fsm_state == TCP_FSM_SYN_RECVD)) {
596 NET_COUNT_MIB(tcp_stats.tcpAttemptFails, 1);
597 }
598
599#endif /* of #ifdef SUPPORT_MIB */
600
601 cep->error = errno;
602 if (TCP_FSM_HAVE_RCVD_SYN(cep->fsm_state)) {
603 cep->fsm_state = TCP_FSM_CLOSED;
604
605 /* 送信と、送信後コネクションの切断を指示する。*/
606 cep->flags |= TCP_CEP_FLG_POST_OUTPUT | TCP_CEP_FLG_CLOSE_AFTER_OUTPUT;
607 sig_sem(SEM_TCP_POST_OUTPUT);
608 }
609 else
610 cep = tcp_close(cep);
611 return cep;
612 }
613
614/*
615 * tcp_respond -- TCP の単一メッセージを送信する。
616 */
617
618void
619tcp_respond (T_NET_BUF *output, T_TCP_CEP *cep,
620 T_TCP_SEQ ack, T_TCP_SEQ seq, uint_t rbfree, uint8_t flags)
621{
622 T_IP_HDR *iph;
623 T_TCP_HDR *tcph;
624 uint_t win = 0;
625
626 if ((flags & TCP_FLG_RST) == 0)
627 win = rbfree;
628
629 /*
630 * output が NULL でなければ、これはå…
631¥åŠ›ã—たセグメントの
632 * net_buf で、そのまま再利用する。
633 */
634 if (output != NULL) {
635 T_IN_ADDR ipaddr;
636 uint16_t portno;
637
638 /*
639 * IPv4 では、IP ヘッダのオプションを削除する。
640 * IPv6 では、拡張ヘッダを削除する。
641 */
642 if (IP_REMOVE_OPTIONS(output) != E_OK) {
643 syscall(rel_net_buf(output));
644 return;
645 }
646
647 iph = GET_IP_HDR(output);
648
649 /* IP アドレスを交換する。*/
650 ipaddr = iph->src;
651 iph->src = iph->dst;
652 iph->dst = ipaddr;
653
654#if defined(SUPPORT_INET6)
655
656 /* トラヒッククラスとフローラベルをクリアする。*/
657 iph->vcf = htonl(IP6_MAKE_VCF(IP6_VCF_V(ntohl(iph->vcf)), 0));
658
659#endif /* of #if defined(SUPPORT_INET6) */
660
661 /* TCP SDU 長を 0 にする。*/
662 SET_IP_SDU_SIZE(iph, TCP_HDR_SIZE);
663
664 tcph = GET_TCP_HDR(output, IF_IP_TCP_HDR_OFFSET);
665
666 /* ポート番号を交換する。*/
667 portno = tcph->sport;
668 tcph->sport = tcph->dport;
669 tcph->dport = portno;
670
671 /* TCP ヘッダに情
672報を設定する。*/
673 tcph->doff = TCP_MAKE_DATA_OFF(TCP_HDR_SIZE);
674 }
675
676 /* cep が NULL であれば、何もしないで終了する。*/
677 else if (cep == NULL)
678 return;
679 else {
680 if (tcp_get_segment(&output, cep, 0,
681 0, (uint_t)(net_buf_max_siz() - IF_IP_TCP_HDR_SIZE),
682 NBA_SEARCH_ASCENT, TMO_TCP_GET_NET_BUF) != E_OK)
683 return;
684 tcph = GET_TCP_HDR(output, IF_IP_TCP_HDR_OFFSET);
685 flags |= TCP_FLG_ACK;
686 }
687
688 tcph->seq = htonl(seq);
689 tcph->ack = htonl(ack);
690 tcph->win = htons(win);
691 tcph->flags = flags;
692 tcph->urp = tcph->sum = 0;
693
694 /*
695 * チェックサムを設定する。
696 */
697 tcph->sum = IN_CKSUM(output, IPPROTO_TCP, IF_IP_TCP_HDR_OFFSET,
698 (uint_t)GET_TCP_HDR_SIZE2(output, IF_IP_TCP_HDR_OFFSET));
699
700 /* ネットワークバッファ長を調整する。*/
701 output->len = (uint16_t)GET_IF_IP_TCP_HDR_SIZE2(output, IF_IP_TCP_HDR_OFFSET);
702
703#ifdef TCP_CFG_TRACE
704
705 tcp_output_trace(output, cep);
706
707#endif /* of #ifdef TCP_CFG_TRACE */
708
709 /* ネットワーク層 (IP) の出力関数を呼び出す。*/
710 IP_OUTPUT(output, TMO_TCP_OUTPUT);
711 }
712
713/*
714 * tcp_set_header -- TCP ヘッダを設定する。
715 */
716
717void
718tcp_set_header (T_NET_BUF *nbuf, T_TCP_CEP *cep, uint_t thoff, uint_t optlen)
719{
720 T_TCP_HDR *tcph = GET_TCP_HDR(nbuf, thoff);
721
722 /* TCP ヘッダに情
723報を設定する。*/
724 tcph->sport = htons(cep->myaddr.portno);
725 tcph->dport = htons(cep->dstaddr.portno);
726 tcph->doff = TCP_MAKE_DATA_OFF(TCP_HDR_SIZE + optlen);
727 tcph->sum = tcph->flags = 0;
728 }
729
730/*
731 * tcp_get_segment -- TCP セグメントを獲得し、ヘッダを設定する。
732 *
733 * 戻り値 エラーコード
734 * optlen オプションサイズ、4 オクテット単位
735 * len TCP SDU サイズ
736 */
737
738ER
739tcp_get_segment (T_NET_BUF **nbuf, T_TCP_CEP *cep,
740 uint_t optlen, uint_t len, uint_t maxlen, ATR nbatr, TMO tmout)
741{
742 ER error;
743
744 /* IP データグラムを獲得する。*/
745 if ((error = IN_GET_DATAGRAM(nbuf,
746 (uint_t)(TCP_HDR_SIZE + optlen + len),
747 (uint_t)(TCP_HDR_SIZE + maxlen),
748 &cep->dstaddr.ipaddr,
749 &cep->myaddr.ipaddr,
750 IPPROTO_TCP, IP_DEFTTL, nbatr, tmout)) != E_OK) {
751 syslog(LOG_WARNING, "[TCP] NET BUF busy, len:%4d, CEP: %d.",
752 (uint16_t)(TCP_HDR_SIZE + optlen + len), GET_TCP_CEPID(cep));
753 return error;
754 }
755
756 /* TCP ヘッダに情
757報を設定する。*/
758 tcp_set_header(*nbuf, cep, IF_IP_TCP_HDR_OFFSET, optlen);
759
760 return E_OK;
761 }
762
763/*
764 * tcp_can_send_more -- 送信できるか、通信端点の状æ…
765‹ã‚’見る。
766 */
767
768ER
769tcp_can_send_more (T_TCP_CEP *cep, FN fncd, TMO tmout)
770{
771 ER error;
772
773 /* 送信できるか、CEP の FSM 状æ…
774‹ã‚’見る。*/
775 if (!TCP_FSM_CAN_SEND_MORE(cep->fsm_state)) {
776 if ((error = cep->error) == E_OK)
777 error = E_OBJ;
778
779#ifdef TCP_CFG_NON_BLOCKING
780
781 /* タイムアウトをチェックする。*/
782 if (tmout == TMO_NBLK) { /* ノンブロッキングコール */
783
784 if (!IS_PTR_DEFINED(cep->callback))
785 error = E_OBJ;
786 else {
787
788#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
789
790 /* コールバック関数を呼び出す。*/
791 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)error);
792
793#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
794
795 /* コールバック関数を呼び出す。*/
796 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)&error);
797
798#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
799
800 error = E_WBLK;
801 }
802 }
803
804#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
805
806 }
807 else {
808
809#ifdef TCP_CFG_SWBUF_CSAVE
810
811 error = E_OK;
812
813#else /* of #ifdef TCP_CFG_SWBUF_CSAVE */
814
815 if (!IS_PTR_DEFINED(cep->sbuf)) {
816
817#ifdef TCP_CFG_NON_BLOCKING
818
819 /* タイムアウトをチェックする。*/
820 if (tmout == TMO_NBLK) { /* ノンブロッキングコール */
821 if (!IS_PTR_DEFINED(cep->callback))
822 error = E_OBJ;
823 else {
824
825#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
826
827 /* コールバック関数を呼び出す。*/
828 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)E_OBJ);
829
830#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
831
832 /* コールバック関数を呼び出す。*/
833 error = E_OBJ;
834 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)&error);
835
836#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
837
838 error = E_WBLK;
839 }
840 }
841 else
842
843#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
844
845 error = E_OBJ;
846 }
847 else
848 error = E_OK;
849
850#endif /* of #ifdef TCP_CFG_SWBUF_CSAVE */
851
852 }
853
854 return error;
855 }
856
857/*
858 * tcp_can_recv_more -- 受信できるか、通信端点の状æ…
859‹ã‚’見る。
860 *
861 * 注意: 戻り値
862 *
863 * E_OK 受信可能
864 * E_OBJ 相手から切断されたか、エラーが発生した。
865 */
866
867ER
868tcp_can_recv_more (ER *error, T_TCP_CEP *cep, FN fncd, TMO tmout)
869{
870 /*
871 * 受信できるか、fsm_state を見る。受信できない場合は
872 * 長さ 0、またはエラーを返す。
873 */
874 if (!TCP_FSM_CAN_RECV_MORE(cep->fsm_state) &&
875 cep->rwbuf_count == 0 && cep->reassq == NULL) {
876 *error = cep->error;
877
878#ifdef TCP_CFG_NON_BLOCKING
879
880 /* タイムアウトをチェックする。*/
881 if (tmout == TMO_NBLK) { /* ノンブロッキングコール */
882
883 if (!IS_PTR_DEFINED(cep->callback))
884 *error = E_OBJ;
885 else {
886#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
887
888 /* コールバック関数を呼び出す。*/
889 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)*error);
890
891#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
892
893 /* コールバック関数を呼び出す。*/
894 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)error);
895
896#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
897
898 *error = E_WBLK;
899 }
900 }
901
902#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
903
904 /*
905 * 通信端点をロックして、
906 * 受信ウィンドバッファキューのネットワークバッファを解放する。
907 */
908 syscall(wai_sem(cep->semid_lock));
909 TCP_FREE_RWBUFQ(cep);
910 syscall(sig_sem(cep->semid_lock));
911
912 return E_OBJ;
913 }
914 else {
915
916#ifndef TCP_CFG_RWBUF_CSAVE
917
918 if (!IS_PTR_DEFINED(cep->rbuf)) {
919
920#ifdef TCP_CFG_NON_BLOCKING
921
922 /* タイムアウトをチェックする。*/
923 if (tmout == TMO_NBLK) { /* ノンブロッキングコール */
924 if (!IS_PTR_DEFINED(cep->callback))
925 *error = E_OBJ;
926 else {
927
928#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
929
930 /* コールバック関数を呼び出す。*/
931 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)E_OBJ);
932
933#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
934
935 /* コールバック関数を呼び出す。*/
936 *error = E_OBJ;
937 (*cep->callback)(GET_TCP_CEPID(cep), fncd, (void*)error);
938
939#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
940
941 *error = E_WBLK;
942 }
943 }
944 else
945
946#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
947
948 *error = E_OBJ;
949
950 return E_OBJ;
951 }
952
953#endif /* of #ifndef TCP_CFG_RWBUF_CSAVE */
954
955 return E_OK;
956 }
957 }
958
959/*
960 * tcp_wait_rwbuf -- 受信ウィンドバッファにデータがå…
961¥ã‚‹ã®ã‚’å¾…
962つ。
963 */
964
965ER
966tcp_wait_rwbuf (T_TCP_CEP *cep, TMO tmout)
967{
968 ER error;
969 FLGPTN flag;
970
971 if (cep->rwbuf_count == 0) {
972 /* 受信ウィンドバッファにデータがなければ、å…
973¥åŠ›ãŒã‚るまで待
974つ。*/
975 while (cep->rwbuf_count == 0) {
976 if ((error = twai_flg(cep->rcv_flgid, TCP_CEP_EVT_RWBUF_READY, TWF_ORW, &flag, tmout)) != E_OK) {
977 return error;
978 }
979 syscall(clr_flg(cep->rcv_flgid, (FLGPTN)(~TCP_CEP_EVT_RWBUF_READY)));
980
981 /*
982 * 受信できるか、fsm_state を見る。受信できない状æ…
983‹ã§ã€
984 * 受信ウィンドバッファに文字がない場合は終了する。
985 */
986 if (!TCP_FSM_CAN_RECV_MORE(cep->fsm_state) &&
987 cep->rwbuf_count == 0 && cep->reassq == NULL) {
988
989 /*
990 * 通信端点をロックして、
991 * 受信ウィンドバッファキューのネットワークバッファを解放する。
992 */
993#ifdef TCP_CFG_RWBUF_CSAVE
994#endif
995 syscall(wai_sem(cep->semid_lock));
996 TCP_FREE_RWBUFQ(cep);
997 syscall(sig_sem(cep->semid_lock));
998
999 return cep->error;
1000 }
1001 }
1002 }
1003 else
1004 syscall(clr_flg(cep->rcv_flgid, (FLGPTN)(~TCP_CEP_EVT_RWBUF_READY)));
1005
1006 return E_OK;
1007 }
1008
1009/*
1010 * tcp_move_ra2rw -- 受信再構成キューで再構成したセグメントを受信ウィンドバッファに書き込む。
1011 */
1012
1013uint8_t
1014tcp_move_ra2rw (T_TCP_CEP *cep, uint8_t flags)
1015{
1016 T_NET_BUF *q;
1017 T_TCP_Q_HDR *qhdr;
1018
1019 /*
1020 * 受信データを受信ウィンドバッファに書き込み、
1021 * rcv_nxt を完了した SEQ だけ進める。
1022 */
1023 if (TCP_FSM_HAVE_ESTABLISHED(cep->fsm_state)) {
1024 while (cep->reassq != NULL) {
1025 q = cep->reassq;
1026 qhdr = GET_TCP_Q_HDR(q, GET_TCP_IP_Q_HDR(q)->thoff);
1027 if (qhdr->seq != cep->rcv_nxt)
1028 break;
1029
1030 /* 次のセグメントに進む。*/
1031 cep->reassq = qhdr->next;
1032
1033 /* FIN フラグのみ残す。*/
1034 flags &= TCP_FLG_FIN;
1035
1036 /* データを受信ウィンドバッファに書き込む。*/
1037 TCP_WRITE_RWBUF(cep, q, (uint_t)(GET_TCP_IP_Q_HDR(q)->thoff));
1038 }
1039 }
1040 if (cep->reassq != NULL) {
1041 cep->flags |= TCP_CEP_FLG_ACK_NOW;
1042 flags &= ~TCP_FLG_FIN;
1043 }
1044 return flags;
1045 }
1046
1047/*
1048 * tcp_write_raque -- 受信セグメントを再構成して、受信再構成キューに繋ぐ。
1049 */
1050
1051uint8_t
1052tcp_write_raque (T_NET_BUF *input, T_TCP_CEP *cep, uint_t thoff, uint8_t flags)
1053{
1054 T_NET_BUF *new;
1055 T_NET_BUF *p, *q, *nq;
1056 T_TCP_Q_HDR *qhdr, *inqhdr = GET_TCP_Q_HDR(input, thoff);
1057 int32_t len;
1058
1059 /* TCP ヘッダの位置を保存する。*/
1060 GET_TCP_IP_Q_HDR(input)->thoff = thoff;
1061
1062 /*
1063 * MAX_TCP_REALLOC_SIZE 以下の場合は、新たにネットワークバッファを
1064 * 割当てて、データをコピーする。
1065 * このとき、IP のオプション(拡張ヘッダ)と TCP のオプションは削除する。
1066 */
1067 len = IF_IP_TCP_HDR_SIZE + inqhdr->slen;
1068
1069 if (len <= MAX_TCP_REALLOC_SIZE) {
1070
1071 /*
1072 * ネットワークバッファが確保できないときは割当てない。
1073 */
1074 if (tget_net_buf(&new, (uint_t)len, TMO_TCP_GET_NET_BUF) != E_OK)
1075 new = NULL;
1076 }
1077 else
1078 new = NULL;
1079
1080 /*
1081 * inqhdr->seq
1082 * |
1083 * |<------- inqhdr->slen ------->|
1084 * v v
1085 * +------------------------------+
1086 * | input |
1087 * +------------------------------+
1088 * ^ ^
1089 * |<----- slen ----->|
1090 * |
1091 * soff
1092 *
1093 */
1094 inqhdr->soff = 0;
1095
1096 /*
1097 * 今回追加するセグメントより前(p)と後(q)のセグメントを探す。
1098 *
1099 * +-------------------------+
1100 * | p |
1101 * +-------------------------+
1102 * ^ +---------------------------+
1103 * p->seq | input |
1104 * +---------------------------+
1105 * ^ +-------------------------+
1106 * inqhdr->seq | q |
1107 * +-------------------------+
1108 * ^
1109 * q->seq
1110 */
1111 for (q = cep->reassq, p = NULL; q != NULL; ) {
1112 qhdr = GET_TCP_Q_HDR(q, GET_TCP_IP_Q_HDR(q)->thoff);
1113 if (SEQ_GT(qhdr->seq, inqhdr->seq))
1114 break;
1115 p = q;
1116 q = qhdr->next;
1117 }
1118
1119 /*
1120 * 前(p)のセグメントがあれば、既に、今回と同じセグメントが
1121 * あることもある。その場合は、その部分またはå…
1122¨ã¦ã‚’破棄する。
1123 *
1124 * qhdr->seq
1125 * |
1126 * |<----- qhdr->slen ------>|
1127 * v v
1128 * +-------------------------+
1129 * | p |
1130 * +-------------------------+
1131 * <--len -->
1132 * +---------------------------+
1133 * | input |
1134 * +---------------------------+
1135 * ^
1136 * inqhdr->seq
1137 */
1138 if (p != NULL) {
1139 qhdr = GET_TCP_Q_HDR(p, GET_TCP_IP_Q_HDR(p)->thoff);
1140 len = qhdr->seq + qhdr->slen - inqhdr->seq;
1141 if (len > 0) {
1142
1143 /*
1144 * len が正であれば、前(p) のセグメントと今回の
1145 * セグメントが重なっている。
1146 */
1147 if (len >= inqhdr->slen) {
1148
1149 /*
1150 * len が今回のセグメントと同じなら
1151 * まったく同じセグメントなので何もしない。
1152 */
1153 if (new != NULL) {
1154 syscall(rel_net_buf(new));
1155 }
1156
1157 syscall(rel_net_buf(input));
1158 return flags;
1159 }
1160
1161 /*
1162 * 追加するセグメントの SDU を len 分前に詰める。
1163 */
1164 inqhdr->seq += len;
1165 inqhdr->soff += (uint16_t)len;
1166 inqhdr->slen -= (uint16_t)len;
1167 }
1168 }
1169
1170 /*
1171 * キューにつなぐ前に、新しいネットワークバッファにデータを移す。
1172 * TCP のオプションは削除する。
1173 */
1174 if (new != NULL) {
1175 memcpy(new->buf, input->buf, (size_t)(thoff + TCP_HDR_SIZE));
1176 memcpy((uint8_t*)GET_TCP_HDR(new, thoff) + TCP_HDR_SIZE,
1177 GET_TCP_SDU(input, thoff), (size_t)(inqhdr->slen));
1178 syscall(rel_net_buf(input));
1179 input = new;
1180 inqhdr = GET_TCP_Q_HDR(input, thoff);
1181 inqhdr->doff = (uint8_t)TCP_MAKE_DATA_OFF(TCP_HDR_SIZE);
1182 }
1183
1184 /*
1185 * 重なる後(q)のセグメントを調整する。
1186 *
1187 * inqhdr->seq
1188 * |
1189 * |<----- inqhdr->slen ---->|
1190 * v v
1191 * +-------------------------+
1192 * | input |
1193 * +-------------------------+
1194 * <--len -->
1195 * +---------------------------+
1196 * | q |
1197 * +---------------------------+
1198 * ^
1199 * qhdr->seq
1200 */
1201 while (q != NULL) {
1202 qhdr = GET_TCP_Q_HDR(q, GET_TCP_IP_Q_HDR(q)->thoff);
1203 len = inqhdr->seq + inqhdr->slen - qhdr->seq;
1204 if (len <= 0)
1205 /* len が負なら重なっていない。*/
1206 break;
1207 else if (len < qhdr->slen) {
1208
1209 /*
1210 * 後ろで重なっているセグメントの SDU を len 分前に詰める。
1211 *
1212 * inqhdr->seq
1213 * |
1214 * |<----- inqhdr->slen ---->|
1215 * v v
1216 * +-------------------------+
1217 * | input |
1218 * +-------------------------+
1219 * <--len -->
1220 * +------+---------------------------+
1221 * | | q |
1222 * +------+---------------------------+
1223 * ^--------->
1224 * qhdr->seq
1225 * qhdr->soff
1226 */
1227 qhdr->seq += len;
1228 qhdr->soff += (uint16_t)len;
1229 qhdr->slen -= (uint16_t)len;
1230 break;
1231 }
1232 nq = qhdr->next;
1233 if (p)
1234 GET_TCP_Q_HDR(p, GET_TCP_IP_Q_HDR(p)->thoff)->next = nq;
1235 else
1236 cep->reassq = nq;
1237 syscall(rel_net_buf(q));
1238 q = nq;
1239 }
1240
1241 if (p == NULL) {
1242 inqhdr->next = cep->reassq;
1243 cep->reassq = input;
1244 }
1245 else {
1246 inqhdr->next = GET_TCP_Q_HDR(p, GET_TCP_IP_Q_HDR(p)->thoff)->next;
1247 GET_TCP_Q_HDR(p, GET_TCP_IP_Q_HDR(p)->thoff)->next = input;
1248 }
1249
1250 return tcp_move_ra2rw(cep, flags);
1251 }
1252
1253/*
1254 * tcp_rexmt_val -- 再送タイムアウト値を返す。
1255 */
1256
1257T_TCP_TIME
1258tcp_rexmt_val (T_TCP_CEP *cep)
1259{
1260 T_TCP_TIME val;
1261
1262 val = ((cep->srtt >> (TCP_SRTT_SHIFT - TCP_DELTA_SHIFT)) + cep->rttvar) >> TCP_DELTA_SHIFT;
1263 if (val < TCP_TVAL_MIN)
1264 return TCP_TVAL_MIN;
1265 else
1266 return val;
1267 }
1268
1269/*
1270 * tcp_init_cep -- 通信端点を初期化する。
1271 */
1272
1273void
1274tcp_init_cep (T_TCP_CEP *cep)
1275{
1276#ifdef TCP_CFG_RWBUF_CSAVE
1277 /*
1278 * 受信ウィンドバッファの省コピー機能を有効にした場合、
1279 * 受信ウィンドバッファがå…
1280¨ã¦è§£æ”¾ã•ã‚Œãªã„ことがあるので、
1281 * ここで解放する。
1282 */
1283 if (cep->rwbufq != NULL) {
1284 cep->rwbuf_count = 0;
1285 TCP_FREE_RWBUFQ(cep);
1286 }
1287#endif /* of #ifdef TCP_CFG_RWBUF_CSAVE */
1288
1289 memset((uint8_t*)cep + offsetof(T_TCP_CEP, timer), 0,
1290 sizeof(T_TCP_CEP) - offsetof(T_TCP_CEP, timer));
1291
1292 cep->sbuf_rptr = cep->sbuf_wptr = cep->sbuf;
1293 cep->rbuf_rptr = cep->rbuf_wptr = cep->rbuf;
1294
1295 cep->maxseg = DEF_TCP_SND_SEG; /* 送信最大セグメントサイズ */
1296 cep->srtt = TCP_TVAL_SRTT_BASE; /* 滑らかな移動平均 */
1297 cep->rttvar = ((TCP_TVAL_RTO_BASE - TCP_TVAL_SRTT_BASE) << TCP_RTTVAR_SHIFT) / 4;
1298 /* 滑らかな分散 */
1299 cep->rxtcur = TCP_TVAL_RTO_BASE; /* 現在の再送値 */
1300 cep->snd_cwnd = MAX_TCP_WIN_SIZE; /* 輻輳ウィンドサイズ */
1301 cep->snd_ssthresh= MAX_TCP_WIN_SIZE; /* 輻輳ウィンドサイズ(snd_cwnd)の 制限値 */
1302
1303 /*
1304 * 以下に関係しないフラグをクリアーする。
1305 * ・送受信ウィンドバッファの省コピー機能
1306 * ・動的な通信端点の生成・削除機能
1307 */
1308 cep->flags &= (TCP_CEP_FLG_WBCS_NBUF_REQ | TCP_CEP_FLG_WBCS_MASK |
1309 TCP_CEP_FLG_DYNAMIC | TCP_CEP_FLG_VALID);
1310
1311 /* セマフォを初期化する。*/
1312 sig_sem (cep->semid_lock);
1313
1314 /* フラグを初期化する。*/
1315 syscall(set_flg(cep->snd_flgid, TCP_CEP_EVT_SWBUF_READY));
1316 syscall(clr_flg(cep->rcv_flgid, TCP_CEP_EVT_RWBUF_READY));
1317 }
1318
1319/*
1320 * tcp_notify -- ICMP エラーの処理
1321 */
1322
1323void
1324tcp_notify (T_NET_BUF *input, ER error)
1325{
1326 T_IP_HDR *iph;
1327 T_TCP_HDR *tcph;
1328 T_TCP_CEP *cep;
1329
1330 iph = GET_IP_HDR(input);
1331 tcph = GET_TCP_HDR(input, GET_TCP_HDR_OFFSET(input));
1332
1333 if ((cep = tcp_find_cep(&iph->src, tcph->sport, &iph->dst, tcph->dport)) != NULL) {
1334
1335 /*
1336 * コネクション開設済で、ホスト到達不能エラーの場合は、
1337 * 再送により処理する。
1338 */
1339 if (cep->fsm_state == TCP_FSM_ESTABLISHED &&
1340 (error == EV_NURCH || error == EV_HURCH || error == EV_HDOWN))
1341 return;
1342
1343 /*
1344 * コネクション開設中、同じエラーを何度か受信した場合は、
1345 * 待
1346ち状æ…
1347‹ã‚’解除し、対応する関数にエラーを返させる。
1348 */
1349 if (cep->fsm_state < TCP_FSM_ESTABLISHED && cep->rxtshift > 3 && cep->net_error != E_OK) {
1350 cep->error = E_CLS;
1351 tcp_close(cep);
1352 }
1353 else {
1354 cep->net_error = error;
1355
1356 /* 送信を指示する。*/
1357 cep->flags |= TCP_CEP_FLG_POST_OUTPUT;
1358 sig_sem(SEM_TCP_POST_OUTPUT);
1359 }
1360 }
1361 }
1362
1363/*
1364 * tcp_find_cep -- ポート番号から TCP 通信端点を得る。
1365 *
1366 * 注意: dstaddr は、
1367 * TINET-1.2 からネットワークバイトオーダ、
1368 * TINET-1.1 までは、ホストバイトオーダ
1369 */
1370
1371T_TCP_CEP*
1372tcp_find_cep (T_IN_ADDR *dstaddr, uint16_t dstport, T_IN_ADDR *peeraddr, uint16_t peerport)
1373{
1374 T_TCP_CEP* cep;
1375
1376 /*
1377 * 状æ…
1378‹ãŒ SYN 送信済み以後は、
1379 * IP アドレスとポート番号が一致する通信端点を探索する。
1380 */
1381 for (cep = &tcp_cep[tmax_tcp_cepid]; cep -- != tcp_cep; ) {
1382 if (cep->fsm_state >= TCP_FSM_SYN_SENT &&
1383 IN_IS_DSTADDR_ACCEPT (&cep->myaddr.ipaddr, dstaddr) &&
1384 IN_ARE_NET_ADDR_EQUAL(&cep->dstaddr.ipaddr, peeraddr) &&
1385 dstport == cep->myaddr.portno &&
1386 peerport == cep->dstaddr.portno)
1387 return cep;
1388 }
1389
1390 /* 受動オープン中の通信端点を探索する。*/
1391 for (cep = &tcp_cep[tmax_tcp_cepid]; cep -- != tcp_cep; ) {
1392 if (cep->fsm_state == TCP_FSM_LISTEN &&
1393 IN_IS_DSTADDR_ACCEPT(&cep->myaddr.ipaddr, dstaddr) &&
1394 dstport == cep->myaddr.portno)
1395 return cep;
1396 }
1397
1398 return NULL;
1399 }
1400
1401/*
1402 * tcp_lock_cep -- TCP 通信端点をロックする。
1403 */
1404
1405ER
1406tcp_lock_cep (ID cepid, T_TCP_CEP **p_cep, FN tfn)
1407{
1408 T_TCP_CEP *cep;
1409 ER error = E_OK;
1410
1411 *p_cep = NULL;
1412
1413 /* TCP 通信端点 ID をチェックする。*/
1414 if (!VAID_TCP_CEPID(cepid))
1415 return E_ID;
1416
1417 /* TCP 通信端点を得る。*/
1418 cep = GET_TCP_CEP(cepid);
1419
1420 /* TCP 通信端点をロックする。*/
1421 syscall(wai_sem(cep->semid_lock));
1422
1423 /* TCP 通信端点をチェックする。*/
1424 if (!VALID_TCP_CEP(cep)) {
1425 syscall(sig_sem(cep->semid_lock));
1426 return E_NOEXS;
1427 }
1428
1429 /*
1430 * API 機能コードとタスク識別子を記録する。
1431 * すでに記録されていれば、ペンディング中なのでエラー
1432 */
1433 if (IS_TFN_TCP_RCV(tfn)) {
1434 if (cep->rcv_tfn != TFN_TCP_UNDEF ||
1435 (tfn == TFN_TCP_ACP_CEP && cep->snd_tfn == TFN_TCP_CON_CEP))
1436 error = E_OBJ;
1437 else {
1438 get_tid(&(cep->rcv_tskid));
1439 cep->rcv_tfn = tfn;
1440 }
1441 }
1442 else {
1443 if (cep->snd_tfn != TFN_TCP_UNDEF ||
1444 (tfn == TFN_TCP_CON_CEP && cep->rcv_tfn == TFN_TCP_ACP_CEP) ||
1445 (tfn == TFN_TCP_CON_CEP && cep->rcv_tfn == TFN_TCP_CLS_CEP))
1446 error = E_OBJ;
1447 else {
1448 get_tid(&(cep->snd_tskid));
1449 cep->snd_tfn = tfn;
1450 }
1451 }
1452
1453 /* 通信端点のロックを解除する。*/
1454 syscall(sig_sem(cep->semid_lock));
1455
1456 *p_cep = cep;
1457 return error;
1458 }
1459
1460#ifdef TCP_CFG_TRACE
1461
1462#ifndef CONSOLE_PORTID
1463#define CONSOLE_PORTID LOGTASK_PORTID
1464#endif
1465
1466/*
1467 * コネクションの状æ…
1468‹
1469 */
1470
1471static const char tcp_strfsm[][3] = {
1472 { 'C', 'D', '\0' },
1473 { 'L', 'I', '\0' },
1474 { 'S', 'S', '\0' },
1475 { 'S', 'R', '\0' },
1476 { 'E', 'S', '\0' },
1477 { 'C', 'W', '\0' },
1478 { 'F', '1', '\0' },
1479 { 'C', 'G', '\0' },
1480 { 'L', 'A', '\0' },
1481 { 'F', '2', '\0' },
1482 { 'T', 'W', '\0' },
1483 };
1484
1485/*
1486 * trace_putchar -- シリアルポートへの文字出力
1487 */
1488
1489static void
1490trace_putchar (ID portid, char ch)
1491{
1492 serial_wri_dat(portid, &ch, 1);
1493 /*cpu_putc(ch);*/
1494 }
1495
1496/*
1497 * シリアルポートへの書式付文字列出力ライブラリ
1498 */
1499
1500/*
1501 * 数値変換のための変換表
1502 */
1503
1504static const char radhex[] = "0123456789abcdef";
1505static const char radHEX[] = "0123456789ABCDEF";
1506
1507/*
1508 * convert -- trace_printf の数値変換
1509 */
1510
1511static int_t
1512convert (ID portid, long_t val, int_t radix,
1513 const char *radchar, int_t width, bool_t minus, char padchar)
1514{
1515 char digits[24];
1516 int_t ix, pad, pchars;
1517
1518 ix = 0;
1519 do {
1520 if (minus)
1521 digits[ix ++] = radchar[val % radix];
1522 else
1523 digits[ix ++] = radchar[(ulong_t)val % radix];
1524 val /= radix;
1525 } while (val != 0);
1526
1527 if (minus)
1528 digits[ix ++] = '-';
1529
1530 if (width > ix)
1531 pchars = width;
1532 else
1533 pchars = ix;
1534
1535 for (pad = ix; pad < width; pad ++)
1536 trace_putchar(portid, padchar);
1537
1538 while (ix -- > 0)
1539 trace_putchar(portid, digits[ix]);
1540
1541 return pchars;
1542 }
1543
1544/*
1545 * trace_printf -- シリアルポートへの書式付文字列出力
1546 */
1547
1548static void
1549trace_printf (ID portid, const char *fmt, ...)
1550{
1551 va_list ap;
1552 ulong_t val;
1553 char padchar, *str;
1554 int_t ch, width, longflag;
1555
1556 va_start(ap, fmt);
1557 while ((ch = *fmt ++) != '\0') {
1558 if (ch != '%') { /* 書式指定以外 */
1559 trace_putchar(portid, (char)ch);
1560 continue;
1561 }
1562
1563 width = longflag = 0;
1564 padchar = ' ';
1565 if ((ch = *fmt ++) == '0') { /* 上位桁の 0 */
1566 padchar = '0';
1567 ch = *fmt ++;
1568 }
1569
1570 while ('0' <= ch && ch <= '9') { /* 出力幅
1571 */
1572 width = width * 10 + ch - '0';
1573 ch = *fmt ++;
1574 }
1575
1576 while (ch == 'l') { /* long (long) の指定 */
1577 longflag ++;
1578 ch = *fmt ++;
1579 }
1580
1581 switch (ch) {
1582 case 'd':
1583 val = longflag ? (ulong_t)va_arg(ap, long_t)
1584 : (ulong_t)va_arg(ap, int_t);
1585 if (val >= 0)
1586 convert(portid, val, 10, radhex, width, false, padchar);
1587 else
1588 convert(portid, -val, 10, radhex, width, true, padchar);
1589 break;
1590
1591 case 'u':
1592 val = longflag ? (ulong_t)va_arg(ap, ulong_t)
1593 : (ulong_t)va_arg(ap, uint_t);
1594 convert(portid, val, 10, radhex, width, false, padchar);
1595 break;
1596
1597 case 'x':
1598 val = longflag ? (ulong_t)va_arg(ap, ulong_t)
1599 : (ulong_t)va_arg(ap, uint_t);
1600 convert(portid, val, 16, radhex, width, false, padchar);
1601 break;
1602
1603 case 'X':
1604 val = longflag ? (ulong_t)va_arg(ap, ulong_t)
1605 : (ulong_t)va_arg(ap, uint_t);
1606 convert(portid, val, 16, radHEX, width, false, padchar);
1607 break;
1608
1609 case 'c':
1610 ch = va_arg(ap, int_t);
1611 trace_putchar(portid, (char)ch);
1612 break;
1613
1614 case 's':
1615 str = va_arg(ap, char*);
1616 while ((ch = *str ++) != '\0')
1617 trace_putchar(portid, (char)ch);
1618 break;
1619
1620 case '%':
1621 trace_putchar(portid, '%');
1622 break;
1623
1624 case '0':
1625 fmt --;
1626 break;
1627
1628 default:
1629 break;
1630 }
1631
1632 }
1633 va_end(ap);
1634 }
1635
1636/*
1637 * TCP フラグ文字列
1638 */
1639
1640static char *
1641get_tcp_flag_str (char *buf, uint8_t flags)
1642{
1643 static char tcp_flag_str[] = "FSRPAU";
1644
1645 int_t bit, mask = 1;
1646
1647 for (bit = 0; bit < sizeof(tcp_flag_str); bit ++) {
1648 buf[sizeof(tcp_flag_str) - bit - 1] = (char)((flags & mask) ? tcp_flag_str[bit] : '-');
1649 mask <<= 1;
1650 }
1651 buf[sizeof(tcp_flag_str)] = '\0';
1652 return buf;
1653 }
1654
1655/*
1656 * 送信 TCP ヘッダのトレース出力
1657 */
1658
1659void
1660tcp_output_trace (T_NET_BUF *output, T_TCP_CEP *cep)
1661{
1662 SYSTIM time;
1663 T_IP_HDR *iph;
1664 T_TCP_HDR *tcph;
1665 char buf[9];
1666
1667 if (!(TCP_CFG_TRACE_LPORTNO == TCP_PORTANY || cep->myaddr.portno == TCP_CFG_TRACE_LPORTNO) ||
1668 !(TCP_CFG_TRACE_RPORTNO == TCP_PORTANY || cep->dstaddr.portno == TCP_CFG_TRACE_RPORTNO))
1669 return;
1670
1671#if defined(SUPPORT_INET4)
1672
1673 if (!(TCP_CFG_TRACE_IPV4_RADDR == IPV4_ADDRANY || cep->dstaddr.ipaddr == TCP_CFG_TRACE_IPV4_RADDR))
1674 return;
1675
1676#endif /* of #if defined(SUPPORT_INET4) */
1677
1678 syscall(wai_sem(SEM_TCP_TRACE));
1679 syscall(get_tim(&time));
1680 iph = GET_IP_HDR(output);
1681 tcph = GET_TCP_HDR(output, GET_TCP_HDR_OFFSET(output));
1682 if (time > 99999999)
1683 trace_printf(CONSOLE_PORTID, "=O%10d", time / 1000);
1684 else
1685 trace_printf(CONSOLE_PORTID, "=O%6d.%03d", time / 1000, time % 1000);
1686 if (cep == NULL)
1687 trace_printf(CONSOLE_PORTID, "=c:-- s:-- f:-----");
1688 else
1689 trace_printf(CONSOLE_PORTID, "=c:%2d s:%s f:%05x",
1690 GET_TCP_CEPID(cep),
1691 tcp_strfsm[cep->fsm_state], cep->flags);
1692 trace_printf(CONSOLE_PORTID, ":%s", get_tcp_flag_str(buf, tcph->flags));
1693 if (cep->fsm_state >= TCP_FSM_ESTABLISHED)
1694 trace_printf(CONSOLE_PORTID, " s:%10u a:%10u",
1695 ntohl(tcph->seq) - cep->iss,
1696 ntohl(tcph->ack) - cep->irs);
1697 else
1698 trace_printf(CONSOLE_PORTID, " s:%10u a:%10u",
1699 ntohl(tcph->seq), ntohl(tcph->ack));
1700 trace_printf(CONSOLE_PORTID, " w:%5d l:%4d>\n",
1701 ntohs(tcph->win),
1702 GET_IP_SDU_SIZE(iph) - TCP_HDR_LEN(tcph->doff));
1703 syscall(sig_sem(SEM_TCP_TRACE));
1704 }
1705
1706/*
1707 * 受信 TCP ヘッダのトレース出力
1708 *
1709 * 注意: TCP ヘッダ内
1710は、すでにホストバイトオーダ
1711 */
1712
1713void
1714tcp_input_trace (T_NET_BUF *input, T_TCP_CEP *cep)
1715{
1716 SYSTIM time;
1717 T_IP_HDR *iph;
1718 T_TCP_HDR *tcph;
1719 char buf[9];
1720
1721 if (!(TCP_CFG_TRACE_LPORTNO == TCP_PORTANY || cep->myaddr.portno == TCP_CFG_TRACE_LPORTNO) ||
1722 !(TCP_CFG_TRACE_RPORTNO == TCP_PORTANY || cep->dstaddr.portno == TCP_CFG_TRACE_RPORTNO))
1723 return;
1724
1725#if defined(SUPPORT_INET4)
1726
1727 if (!(TCP_CFG_TRACE_IPV4_RADDR == IPV4_ADDRANY || cep->dstaddr.ipaddr == TCP_CFG_TRACE_IPV4_RADDR))
1728 return;
1729
1730#endif /* of #if defined(SUPPORT_INET4) */
1731
1732 syscall(wai_sem(SEM_TCP_TRACE));
1733 syscall(get_tim(&time));
1734 iph = GET_IP_HDR(input);
1735 tcph = GET_TCP_HDR(input, GET_TCP_HDR_OFFSET(input));
1736 if (time > 99999999)
1737 trace_printf(CONSOLE_PORTID, "<I%10d", time / 1000);
1738 else
1739 trace_printf(CONSOLE_PORTID, "<I%6d.%03d", time / 1000, time % 1000);
1740 if (cep == NULL)
1741 trace_printf(CONSOLE_PORTID, "=c:-- s:-- f:-----");
1742 else
1743 trace_printf(CONSOLE_PORTID, "=c:%2d s:%s f:%05x",
1744 GET_TCP_CEPID(cep),
1745 tcp_strfsm[cep->fsm_state], cep->flags);
1746 trace_printf(CONSOLE_PORTID, ":%s", get_tcp_flag_str(buf, tcph->flags));
1747 if (cep->fsm_state >= TCP_FSM_SYN_RECVD)
1748 trace_printf(CONSOLE_PORTID, " a:%10u s:%10u", tcph->ack - cep->iss, tcph->seq - cep->irs);
1749 else
1750 trace_printf(CONSOLE_PORTID, " a:%10u s:%10u", tcph->ack, tcph->seq);
1751 trace_printf(CONSOLE_PORTID, " w:%5d l:%4d=\n",
1752 tcph->win, GET_IP_SDU_SIZE(iph) - TCP_HDR_LEN(tcph->doff));
1753 syscall(sig_sem(SEM_TCP_TRACE));
1754 }
1755
1756#endif /* of #ifdef TCP_CFG_TRACE */
1757
1758#endif /* of #ifdef SUPPORT_TCP */
Note: See TracBrowser for help on using the repository browser.