source: EcnlProtoTool/trunk/asp3_dcre/tinet/netinet/tcp_subr.c@ 321

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

文字コードを設定

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