source: EcnlProtoTool/trunk/asp3_dcre/tinet/netinet/tcp_subr_cs.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: 33.0 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 <string.h>
71
72#ifdef TARGET_KERNEL_ASP
73
74#include <kernel.h>
75#include <sil.h>
76#include <t_syslog.h>
77#include "kernel_cfg.h"
78
79#endif /* of #ifdef TARGET_KERNEL_ASP */
80
81#ifdef TARGET_KERNEL_JSP
82
83#include <s_services.h>
84#include <t_services.h>
85#include "kernel_id.h"
86
87#endif /* of #ifdef TARGET_KERNEL_JSP */
88
89#include <tinet_defs.h>
90#include <tinet_config.h>
91
92#include <net/if.h>
93#include <net/if_ppp.h>
94#include <net/if_loop.h>
95#include <net/ethernet.h>
96#include <net/if_arp.h>
97#include <net/ppp_ipcp.h>
98#include <net/net.h>
99#include <net/net_var.h>
100#include <net/net_buf.h>
101#include <net/net_timer.h>
102#include <net/net_count.h>
103
104#include <netinet/in.h>
105#include <netinet6/in6.h>
106#include <netinet6/in6_var.h>
107#include <netinet/in_var.h>
108#include <netinet/ip.h>
109#include <netinet/ip_var.h>
110#include <netinet/ip6.h>
111#include <netinet6/ip6_var.h>
112#include <netinet6/nd6.h>
113#include <netinet/tcp.h>
114#include <netinet/tcp_timer.h>
115#include <netinet/tcp_var.h>
116#include <netinet/tcp_fsm.h>
117#include <netinet/tcp_seq.h>
118#include <netinet/in_itron.h>
119
120#ifdef SUPPORT_TCP
121
122#ifdef TCP_CFG_SWBUF_CSAVE
123
124#ifndef TCP_CFG_SWBUF_CSAVE_ONLY
125
126/*
127 * TCP 通信端点の送信ウィンドバッファの省コピー機能が有効な場合
128 * ただし、通信端点の送信ウィンドバッファ(cep->sbuf)の値により、
129 * TCP 通信端点毎に送信ウィンドバッファの省コピー機能を使用するか、
130 * 使用しないかを切り替える。
131 */
132
133/*
134 * tcp_drop_swbuf -- 送信ウィンドバッファから指定されたオクテット分削除する(選択)。
135 */
136
137void
138tcp_drop_swbuf (T_TCP_CEP *cep, uint_t len)
139{
140 if (IS_PTR_DEFINED(cep->sbuf))
141 tcp_drop_swbuf_ncs(cep, len);
142 else
143 tcp_drop_swbuf_cs(cep, len);
144 }
145
146/*
147 * tcp_write_swbuf -- 送信ウィンドバッファにデータを書き込む(選択)。
148 */
149
150ER_UINT
151tcp_write_swbuf (T_TCP_CEP *cep, void *data, uint_t len)
152{
153 if (IS_PTR_DEFINED(cep->sbuf))
154 return tcp_write_swbuf_ncs(cep, data, len);
155 else
156 return tcp_write_swbuf_cs(cep, data, len);
157 }
158
159/*
160 * tcp_read_swbuf -- 送信ウィンドバッファからデータを読み出す(選択)。
161 */
162
163void
164tcp_read_swbuf (T_TCP_CEP *cep, T_NET_BUF *output, uint_t len, uint_t doff)
165{
166 if (IS_PTR_DEFINED(cep->sbuf))
167 tcp_read_swbuf_ncs(cep, output, len, doff);
168 }
169
170/*
171 * tcp_wait_swbuf -- 送信ウィンドバッファと相手の受信ウィンドが開くのを待つ(選択)。
172 */
173
174ER
175tcp_wait_swbuf (T_TCP_CEP *cep, TMO tmout)
176{
177 if (IS_PTR_DEFINED(cep->sbuf))
178 return tcp_wait_swbuf_ncs(cep, tmout);
179 else
180 return tcp_wait_swbuf_cs(cep, tmout);
181 }
182
183/*
184 * tcp_get_swbuf_addr -- 送信ウィンドバッファの空きアドレスを獲得する(選択)。
185 */
186
187ER_UINT
188tcp_get_swbuf_addr (T_TCP_CEP *cep, void **p_buf)
189{
190 if (IS_PTR_DEFINED(cep->sbuf))
191 return tcp_get_swbuf_addr_ncs(cep, p_buf);
192 else
193 return tcp_get_swbuf_addr_cs(cep, p_buf);
194 }
195
196/*
197 * tcp_send_swbuf -- 送信ウィンドバッファのデータを送信可能にする(選択)。
198 */
199
200void
201tcp_send_swbuf (T_TCP_CEP *cep, uint_t len)
202{
203 if (IS_PTR_DEFINED(cep->sbuf))
204 tcp_send_swbuf_ncs(cep, len);
205 else
206 tcp_send_swbuf_cs(cep, len);
207 }
208
209/*
210 * tcp_free_swbufq -- 送信ウィンドバッファキューの解放を指示する(選択)。
211 */
212
213void
214tcp_free_swbufq (T_TCP_CEP *cep)
215{
216 if (!IS_PTR_DEFINED(cep->sbuf))
217 tcp_free_swbufq_cs(cep);
218 }
219
220/*
221 * tcp_alloc_swbuf -- 送信ウィンドバッファ用のネットワークバッファの割り当てを指示する(選択)。
222 */
223
224void
225tcp_alloc_swbuf (T_TCP_CEP *cep)
226{
227 if (!IS_PTR_DEFINED(cep->sbuf))
228 tcp_alloc_swbuf_cs(cep);
229 }
230
231/*
232 * tcp_is_swbuf_full -- 送信ウィンドバッファが満杯かチェックする(選択)。
233 */
234
235bool_t
236tcp_is_swbuf_full (T_TCP_CEP *cep)
237{
238 if (IS_PTR_DEFINED(cep->sbuf))
239 return tcp_is_swbuf_full_ncs(cep);
240 else
241 return tcp_is_swbuf_full_cs(cep);
242 }
243
244#endif /* of #ifndef TCP_CFG_SWBUF_CSAVE_ONLY */
245
246/*
247 * tcp_drop_swbuf_cs -- 送信ウィンドバッファから指定されたオクテット分削除する(専用)。
248 */
249
250void
251tcp_drop_swbuf_cs (T_TCP_CEP *cep, uint_t len)
252{
253
254 /*送信ウィンドバッファから指定されたオクテット分削除する。*/
255 cep->swbuf_count -= (uint16_t)len;
256
257 /* 送信済みで、ACK待ちの時は、ACK完了に変更する。*/
258 if (len > 0 && (cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_SENT) {
259 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_ACKED;
260 sig_sem(SEM_TCP_POST_OUTPUT);
261 }
262 }
263
264/*
265 * tcp_write_swbuf_cs -- 送信ウィンドバッファにデータを書き込む(専用)。
266 */
267
268ER_UINT
269tcp_write_swbuf_cs (T_TCP_CEP *cep, void *data, uint_t len)
270{
271 ER_UINT error;
272
273 /* 通信端点をロックする。*/
274 syscall(wai_sem(cep->semid_lock));
275
276 if ((error = net_buf_siz(cep->swbufq)) > 0 && error >= IF_IP_TCP_HDR_SIZE) {
277
278
279 /*
280 * +-----------+--------+---------+---------+
281 * | Ehter HDR | IP HDR | TCP HDR | TCP SDU |
282 * +-----------+--------+---------+---------+
283 * 14 20 20 n
284 * <---------------- error --------------->
285 * ^
286 * net_buf で 4 オクテット境界にアラインされている。
287 *
288 * tcp_output と ip_output で、チェックサムを計算するとき、
289 * n が 4 オクテット境界になるように SDU の後ろに 0 を
290 * パッディングする。その分を考慮して送信ウィンドバッファの
291 * 空きサイズを 4 オクテット境界に調整する。
292 */
293 error = (uint_t)(((error - IF_IP_TCP_HDR_SIZE) >> 2 << 2) + IF_IP_TCP_HDR_SIZE);
294
295 if (len > cep->sbufsz - cep->swbuf_count)
296 len = (uint_t)(cep->sbufsz - cep->swbuf_count);
297 if (len > (error - IF_IP_TCP_HDR_SIZE))
298 len = (uint_t)(error - IF_IP_TCP_HDR_SIZE);
299
300 /* 送信ウインドサイズによりサイズを調整する。*/
301 if (len > cep->snd_wnd)
302 len = cep->snd_wnd;
303 if (len > cep->snd_cwnd)
304 len = cep->snd_cwnd;
305
306 /* 相手の最大受信セグメントサイズ (maxseg) を超えないようにする。*/
307 if (len > cep->maxseg)
308 len = cep->maxseg;
309
310 /* データを移す。*/
311 memcpy(cep->sbuf_wptr, (void*)((uint8_t*)data), (size_t)len);
312 cep->sbuf_wptr += len;
313 cep->swbuf_count += len;
314 error = len;
315
316 /* ネットワークバッファ長と IP データグラム長を設定する。*/
317 cep->swbufq->len = (uint16_t)(cep->swbuf_count + IF_IP_TCP_HDR_SIZE);
318 SET_IP_SDU_SIZE(GET_IP_HDR(cep->swbufq), cep->swbuf_count + TCP_HDR_SIZE);
319
320 /* フラグを、送信可能に設定する。*/
321 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_SEND_READY;
322 }
323
324 else { /* 送信ウインドバッファが不正 */
325 syslog(LOG_WARNING, "[TCP] illegal window buff for send, CEP: %d, %4d < %4d.",
326 GET_TCP_CEPID(cep), error, IF_IP_TCP_HDR_SIZE);
327
328 /* 送信ウィンドバッファキューのネットワークバッファを解放する。*/
329 tcp_free_swbufq_cs(cep);
330 }
331
332 /* 通信端点のロックを解除する。*/
333 syscall(sig_sem(cep->semid_lock));
334
335 return error;
336 }
337
338/*
339 * tcp_wait_swbuf_cs -- 送信ウィンドバッファと相手の受信ウィンドが開くのを待つ(専用)。
340 */
341
342ER
343tcp_wait_swbuf_cs (T_TCP_CEP *cep, TMO tmout)
344{
345 FLGPTN flag;
346 SYSTIM before, after;
347 ER error;
348 int_t win;
349
350
351 /* 送信ウィンドバッファが割当て済みで、空きがあれば終了する。*/
352 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_NBUF_READY &&
353 (cep->swbuf_count + IF_IP_TCP_HDR_SIZE) < net_buf_siz(cep->swbufq))
354 return E_OK;
355
356 /* 送信中であれば、終了するまで待機する。*/
357 while ((cep->flags & TCP_CEP_FLG_WBCS_MASK) != TCP_CEP_FLG_WBCS_FREE) {
358
359 /* 送信待ちの時間を tmout から減ずる。*/
360 if (!(tmout == TMO_POL || tmout == TMO_FEVR))
361 syscall(get_tim(&before));
362
363 if ((error = twai_flg(cep->snd_flgid, TCP_CEP_EVT_SWBUF_READY,
364 TWF_ORW, &flag, tmout)) != E_OK)
365 return error;
366 syscall(clr_flg(cep->snd_flgid, (FLGPTN)(~TCP_CEP_EVT_SWBUF_READY)));
367
368 /* 送信待ちの時間を tmout から減ずる。*/
369 if (!(tmout == TMO_POL || tmout == TMO_FEVR)) {
370 syscall(get_tim(&after));
371 if (after - before > tmout)
372 return E_TMOUT;
373 tmout -= (TMO)(after - before);
374 }
375
376 /*
377 * 送信できるか、CEP の FSM 状態を見る。
378 * 送信ウインドバッファが空くまで待つ間に、送信不能になった場合は、
379 * コネクションが切断されたことを意味している。
380 */
381 if (!TCP_FSM_CAN_SEND_MORE(cep->fsm_state))
382 return E_CLS;
383 }
384
385 /* 相手の受信ウィンドが閉じている場合は、開くまで待機する。*/
386 while (true) {
387
388 /*
389 * snd_wnd: 相手の受信可能ウィンドサイズ
390 * snd_cwnd: 輻輳ウィンドサイズ
391 *
392 * win: どちらか小さいウィンドサイズに設定する。
393 */
394 win = cep->snd_wnd < cep->snd_cwnd ? cep->snd_wnd : cep->snd_cwnd;
395 if (win > 0)
396 break;
397
398 /* 開き待ちの時間を tmout から減ずる。*/
399 if (!(tmout == TMO_POL || tmout == TMO_FEVR))
400 syscall(get_tim(&before));
401
402 if ((error = twai_flg(cep->snd_flgid, TCP_CEP_EVT_SWBUF_READY,
403 TWF_ORW, &flag, tmout)) != E_OK)
404 return error;
405 syscall(clr_flg(cep->snd_flgid, (FLGPTN)(~TCP_CEP_EVT_SWBUF_READY)));
406
407 /* 開き待ちの時間を tmout から減ずる。*/
408 if (!(tmout == TMO_POL || tmout == TMO_FEVR)) {
409 syscall(get_tim(&after));
410 if (after - before > tmout)
411 return E_TMOUT;
412 tmout -= (TMO)(after - before);
413 }
414
415 /*
416 * 送信できるか、CEP の FSM 状態を見る。
417 * 送信ウインドバッファが空くまで待つ間に、送信不能になった場合は、
418 * コネクションが切断されたことを意味している。
419 */
420 if (!TCP_FSM_CAN_SEND_MORE(cep->fsm_state))
421 return E_CLS;
422 }
423
424 /* ネットワークバッファを獲得する。*/
425 if ((error = tcp_get_segment(&cep->swbufq, cep, 0,
426 TCP_CFG_SWBUF_CSAVE_MIN_SIZE,
427 TCP_CFG_SWBUF_CSAVE_MAX_SIZE - IF_IP_TCP_HDR_SIZE,
428 NBA_SEARCH_DESCENT, tmout)) != E_OK)
429 return error;
430
431 /* 送信ウィンドバッファを初期化する。*/
432 tcp_init_swbuf(cep);
433
434 return E_OK;
435 }
436
437/*
438 * tcp_get_swbuf_addr_cs -- 送信ウィンドバッファの空きアドレスを獲得する(専用)。
439 */
440
441ER_UINT
442tcp_get_swbuf_addr_cs (T_TCP_CEP *cep, void **p_buf)
443{
444 ER_UINT error;
445
446 /* 通信端点をロックする。*/
447 syscall(wai_sem(cep->semid_lock));
448
449 if ((error = net_buf_siz(cep->swbufq)) > 0) {
450
451 /*
452 * +-----------+--------+---------+---------+
453 * | Ehter HDR | IP HDR | TCP HDR | TCP SDU |
454 * +-----------+--------+---------+---------+
455 * 14 20 20 n
456 * <---------------- error --------------->
457 * ^
458 * net_buf で 4 オクテット境界にアラインされている。
459 *
460 * tcp_output と ip_output で、チェックサムを計算するとき、
461 * n が 4 オクテット境界になるように SDU の後ろに 0 を
462 * パッディングする。その分を考慮して送信ウィンドバッファの
463 * 空きサイズを 4 オクテット境界に調整する。
464 */
465 error = (uint_t)(((error - IF_IP_TCP_HDR_SIZE) >> 2 << 2) - cep->swbuf_count);
466
467 /* 送信ウインドサイズによりサイズを調整する。*/
468 if (error > cep->snd_wnd)
469 error = cep->snd_wnd;
470 if (error > cep->snd_cwnd)
471 error = cep->snd_cwnd;
472
473 /* 相手の最大受信セグメントサイズ (maxseg) を超えないようにする。*/
474 if (error > cep->maxseg)
475 error = cep->maxseg;
476
477 /* 送信ウィンドバッファの空きデータ長を設定し、その値を返す。*/
478 cep->get_buf_len = error;
479
480 /* 送信ウィンドバッファの空きアドレスの先頭を設定する。*/
481 *p_buf = cep->sbuf_wptr;
482 }
483
484 else { /* ネットワークバッファが不正 */
485
486 /* 送信ウィンドバッファキューのネットワークバッファを解放する。*/
487 tcp_free_swbufq_cs(cep);
488 }
489
490 /* 通信端点のロックを解除する。*/
491 syscall(sig_sem(cep->semid_lock));
492
493 return error;
494 }
495
496/*
497 * tcp_send_swbuf_cs -- 送信ウィンドバッファのデータを送信可能にする(専用)。
498 */
499
500void
501tcp_send_swbuf_cs (T_TCP_CEP *cep, uint_t len)
502{
503 /* 通信端点をロックする。*/
504 syscall(wai_sem(cep->semid_lock));
505
506 cep->sbuf_wptr += len;
507 cep->swbuf_count += len;
508
509 /* ネットワークバッファ長と IP データグラム長を設定する。*/
510 cep->swbufq->len = (uint16_t)(cep->swbuf_count + IF_IP_TCP_HDR_SIZE);
511 SET_IP_SDU_SIZE(GET_IP_HDR(cep->swbufq), len + TCP_HDR_SIZE);
512
513 /* tcp_get_buf の割当て長をリセットする。*/
514 cep->get_buf_len = 0;
515
516 /* 通信端点のロックを解除する。*/
517 syscall(sig_sem(cep->semid_lock));
518
519 /* フラグを、送信可能に設定し、強制的に送信する。*/
520 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_SEND_READY
521 | TCP_CEP_FLG_FORCE
522 | TCP_CEP_FLG_FORCE_CLEAR
523 | TCP_CEP_FLG_POST_OUTPUT;
524 }
525
526/*
527 * tcp_free_swbufq_cs -- 送信ウィンドバッファキューの解放を指示する(専用)。
528 *
529 * 注意:
530 * 必要であれば、この関数を呼び出す前に、通信端点をロックし、
531 * 戻った後、解除する必要がある。
532 */
533
534void
535tcp_free_swbufq_cs (T_TCP_CEP *cep)
536{
537 /* 送信ウィンドバッファの空き待ちを取り消す。*/
538 cep->flags &= ~TCP_CEP_FLG_WBCS_NBUF_REQ;
539
540 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) != TCP_CEP_FLG_WBCS_FREE) {
541 /*
542 * 送信ウィンドバッファを削除するために、フラグを ACK 完了に設定し、
543 * TCP 出力タスクを起動する。
544 */
545 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_ACKED;
546 sig_sem(SEM_TCP_POST_OUTPUT);
547 }
548 }
549
550/*
551 * tcp_alloc_swbuf_cs -- 送信ウィンドバッファ用のネットワークバッファの割り当てを指示する(専用)。
552 */
553
554void
555tcp_alloc_swbuf_cs (T_TCP_CEP *cep)
556{
557 cep->flags |= TCP_CEP_FLG_WBCS_NBUF_REQ;
558
559 /*
560 * 送信ウィンドバッファが未使用の場合のみ、
561 * 送信ウィンドバッファ用のネットワークバッファの割り当てを指示する。
562 */
563 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_FREE)
564 sig_sem(SEM_TCP_POST_OUTPUT);
565 }
566
567/*
568 * tcp_is_swbuf_full_cs -- 送信ウィンドバッファが満杯かチェックする(専用)。
569 */
570
571bool_t
572tcp_is_swbuf_full_cs (T_TCP_CEP *cep)
573{
574 return (cep->flags & TCP_CEP_FLG_WBCS_MASK) != TCP_CEP_FLG_WBCS_NBUF_READY ||
575 cep->swbuf_count >= cep->swbufq->len - IF_IP_TCP_HDR_SIZE;
576 }
577
578/*
579 * tcp_init_swbuf -- 送信ウィンドバッファを初期化する(専用)。
580 *
581 * 注意: tcp_get_segment でネットワークバッファを獲得した
582 * 直後に呼び出すこと。
583 */
584
585void
586tcp_init_swbuf (T_TCP_CEP *cep)
587{
588 /* 送信ウインドバッファの使用中サイズをリセットする。*/
589 cep->swbuf_count = 0;
590
591 /* 送信ウインドバッファのアドレスを設定する。*/
592 cep->sbuf_wptr = cep->sbuf_rptr = GET_TCP_SDU(cep->swbufq, IF_IP_TCP_HDR_OFFSET);
593
594 /* フラグを、ネットワークバッファ割当て済みに設定する。*/
595 cep->flags = (cep->flags & ~(TCP_CEP_FLG_WBCS_NBUF_REQ | TCP_CEP_FLG_WBCS_MASK))
596 | TCP_CEP_FLG_WBCS_NBUF_READY;
597 }
598
599/*
600 * tcp_push_res_nbuf -- ネットワークバッファを予約する(専用)。
601 */
602
603T_NET_BUF *
604tcp_push_res_nbuf (T_NET_BUF *nbuf)
605{
606 static int_t last_ix = 0;
607
608 T_TCP_CEP *cep;
609 int_t ix, sel_ix;
610
611 if (++ last_ix == tmax_tcp_cepid)
612 last_ix = 0;
613 sel_ix = ix = last_ix;
614 do {
615 cep = &tcp_cep[ix];
616 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_NBUF_PEND) {
617
618 /* ネットワークバッファを予約する。*/
619 cep->swbufq = nbuf;
620 nbuf = NULL;
621
622 /* フラグを予約に設定する。*/
623 cep->flags = (cep->flags & ~TCP_CEP_FLG_WBCS_MASK) | TCP_CEP_FLG_WBCS_NBUF_RSVD;
624 sel_ix = ix;
625 break;
626 }
627 if (++ ix == tmax_tcp_cepid)
628 ix = 0;
629 } while (ix != last_ix);
630
631 last_ix = sel_ix;
632
633 return nbuf;
634 }
635
636/*
637 * tcp_pull_res_nbuf -- 予約してあるネットワークバッファ返す(専用)。
638 */
639
640T_NET_BUF *
641tcp_pull_res_nbuf (ATR nbatr)
642{
643 T_NET_BUF *nbuf;
644 T_TCP_CEP *cep;
645
646 cep = GET_TCP_CEP(nbatr & NBA_ID_MASK);
647 if ((cep->flags & TCP_CEP_FLG_WBCS_MASK) == TCP_CEP_FLG_WBCS_NBUF_RSVD) {
648
649 /* 予約してあるネットワークバッファを返す。*/
650 nbuf = cep->swbufq;
651 cep->swbufq = NULL;
652
653 /* TCP 出力タスクを起動する。*/
654 sig_sem(SEM_TCP_POST_OUTPUT);
655 }
656 else
657 nbuf = NULL;
658
659 return nbuf;
660 }
661
662#endif /* of #ifdef TCP_CFG_SWBUF_CSAVE */
663
664#ifdef TCP_CFG_RWBUF_CSAVE
665
666#ifndef TCP_CFG_RWBUF_CSAVE_ONLY
667
668/*
669 * TCP 通信端点の受信ウィンドバッファの省コピー機能が有効な場合
670 * ただし、通信端点の受信ウィンドバッファ(cep->rbuf)の値により、
671 * TCP 通信端点毎に受信ウィンドバッファの省コピー機能を使用するか、
672 * 使用しないかを切り替える。
673 */
674
675/*
676 * tcp_drop_rwbuf -- 受信ウィンドバッファキューの最初のネットワークバッファを解放する。
677 */
678
679void
680tcp_drop_rwbuf (T_TCP_CEP *cep, uint_t len)
681{
682 if (IS_PTR_DEFINED(cep->rbuf))
683 tcp_drop_rwbuf_ncs(cep, len);
684 else
685 tcp_drop_rwbuf_cs(cep, len);
686 }
687
688/*
689 * tcp_read_rwbuf -- 受信ウィンドバッファから指定されたオクテット分読み出す。
690 */
691
692uint_t
693tcp_read_rwbuf (T_TCP_CEP *cep, void *data, uint_t len)
694{
695 if (IS_PTR_DEFINED(cep->rbuf))
696 return tcp_read_rwbuf_ncs(cep, data, len);
697 else
698 return tcp_read_rwbuf_cs(cep, data, len);
699 }
700
701/*
702 * tcp_get_rwbuf_addr -- 受信ウィンドバッファの空きアドレスを獲得する。
703 */
704
705uint_t
706tcp_get_rwbuf_addr (T_TCP_CEP *cep, void **p_buf)
707{
708 if (IS_PTR_DEFINED(cep->rbuf))
709 return tcp_get_rwbuf_addr_ncs(cep, p_buf);
710 else
711 return tcp_get_rwbuf_addr_cs(cep, p_buf);
712 }
713
714/*
715 * tcp_free_rwbufq -- 受信ウィンドバッファキューを解放する。
716 */
717
718void
719tcp_free_rwbufq (T_TCP_CEP *cep)
720{
721 if (!IS_PTR_DEFINED(cep->rbuf))
722 tcp_free_rwbufq_cs(cep);
723 }
724
725/*
726 * tcp_write_rwbuf -- 受信ウィンドバッファにデータを書き込む。
727 */
728
729void
730tcp_write_rwbuf (T_TCP_CEP *cep, T_NET_BUF *input, uint_t thoff)
731{
732 if (IS_PTR_DEFINED(cep->rbuf))
733 tcp_write_rwbuf_ncs(cep, input, thoff);
734 else
735 tcp_write_rwbuf_cs(cep, input, thoff);
736 }
737
738#endif /* of #ifndef TCP_CFG_RWBUF_CSAVE_ONLY */
739
740/*
741 * TCP 通信端点の受信ウィンドバッファの省コピー機能が有効
742 */
743
744/*
745 * tcp_drop_rwbuf -- 受信ウィンドバッファキューの最初のネットワークバッファを解放する。
746 */
747
748void
749tcp_drop_rwbuf_cs (T_TCP_CEP *cep, uint_t len)
750{
751 T_TCP_Q_HDR *qhdr;
752
753 if (cep->rwbufq != NULL) {
754
755 qhdr = GET_TCP_Q_HDR(cep->rwbufq, GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff);
756 cep->rwbuf_count -= len;
757
758 /* ネットワークバッファにデータが無くなったら解放する。*/
759 if (len == qhdr->slen) {
760 T_NET_BUF *next;
761
762#ifdef TCP_CFG_RWBUF_CSAVE_MAX_QUEUES
763
764 cep->rwbufq_entries --;
765
766#endif /* of #ifdef TCP_CFG_RWBUF_CSAVE_MAX_QUEUES */
767
768 next = qhdr->next;
769 syscall(rel_net_buf(cep->rwbufq));
770 cep->rwbufq = next;
771 }
772 else {
773 qhdr->slen -= len;
774 qhdr->soff += len;
775 }
776 }
777 }
778
779/*
780 * tcp_read_rwbuf -- 受信ウィンドバッファから指定されたオクテット分読み出す。
781 */
782
783uint_t
784tcp_read_rwbuf_cs (T_TCP_CEP *cep, void *data, uint_t len)
785{
786 T_TCP_Q_HDR *qhdr;
787 uint_t blen, rlen = 0;
788 uint8_t *buf = (uint8_t*)data;
789
790 /* 通信端点をロックする。*/
791 syscall(wai_sem(cep->semid_lock));
792
793 /*
794 * 受信ウィンドバッファキューにネットワークバッファが無くなるか
795 * len が 0 になるまで続ける。
796 */
797 while (cep->rwbufq != NULL && len > 0) {
798 qhdr = GET_TCP_Q_HDR(cep->rwbufq, GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff);
799
800 /*
801 * len と受信ウィンドバッファキューの先頭ネットワークバッファの
802 * データ数の小さい方を移すデータ数にする。
803 */
804 if (len > qhdr->slen)
805 blen = qhdr->slen;
806 else
807 blen = len;
808
809 memcpy(buf,
810 GET_TCP_SDU(cep->rwbufq, GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff) + qhdr->soff,
811 (size_t)blen);
812
813 /*
814 * 受信ウィンドバッファキューのネットワークバッファに
815 * データが無くなったら解放する。
816 */
817 tcp_drop_rwbuf_cs(cep, blen);
818
819 buf += blen;
820 rlen += blen;
821 len -= blen;
822 }
823
824 /* 通信端点のロックを解除する。*/
825 syscall(sig_sem(cep->semid_lock));
826
827 return rlen;
828 }
829
830/*
831 * tcp_get_rwbuf_addr -- 受信ウィンドバッファの空きアドレスを獲得する。
832 */
833
834uint_t
835tcp_get_rwbuf_addr_cs (T_TCP_CEP *cep, void **p_buf)
836{
837 T_TCP_Q_HDR *qhdr;
838 uint_t len;
839
840 /* 通信端点をロックする。*/
841 syscall(wai_sem(cep->semid_lock));
842
843 if (cep->rwbufq == NULL) {
844
845 /* 受信ウィンドバッファが全て開放されているとき。*/
846 *p_buf = NULL;
847 len = 0;
848 }
849 else {
850
851 /* 受信ウィンドバッファのデータのアドレスの先頭を設定する。*/
852 qhdr = GET_TCP_Q_HDR(cep->rwbufq, GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff);
853 *p_buf = GET_TCP_SDU(cep->rwbufq, GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff) + qhdr->soff;
854
855 /* 受信ウィンドバッファのデータ長を計算する。*/
856 len = qhdr->slen;
857 }
858
859 /* 通信端点のロックを解除する。*/
860 syscall(sig_sem(cep->semid_lock));
861
862 /* 受信ウィンドバッファのデータ長を設定し、その値を返す。*/
863 cep->rcv_buf_len = len;
864 return len;
865 }
866
867/*
868 * tcp_free_rwbufq -- 受信ウィンドバッファキューを解放する。
869 *
870 * 注意:
871 * 必要であれば、この関数を呼び出す前に、通信端点をロックし、
872 * 戻った後、解除する必要がある。
873 */
874
875void
876tcp_free_rwbufq_cs (T_TCP_CEP *cep)
877{
878 T_NET_BUF *next;
879
880 if (cep->rwbuf_count == 0 && cep->reassq == NULL) {
881 while (cep->rwbufq != NULL) {
882 next = GET_TCP_Q_HDR(cep->rwbufq, GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff)->next;
883
884#ifdef TCP_CFG_RWBUF_CSAVE_MAX_QUEUES
885
886 cep->rwbufq_entries --;
887
888#endif /* of #ifdef TCP_CFG_RWBUF_CSAVE_MAX_QUEUES */
889
890 syscall(rel_net_buf(cep->rwbufq));
891 cep->rwbufq = next;
892 }
893
894 /* 受信ウィンドバッファの使用中サイズをリセットする。*/
895 cep->rwbuf_count = 0;
896 }
897 }
898
899/*
900 * tcp_write_rwbuf -- 受信ウィンドバッファにデータを書き込む。
901 *
902 * 注意:
903 * 入力 input は、T_TCP_Q_HDR によりリンクされ、
904 * 並べ替えが終了していなければならない。また、
905 * 追加するデータは、受信ウィンドバッファに収まること。
906 */
907
908void
909tcp_write_rwbuf_cs (T_TCP_CEP *cep, T_NET_BUF *input, uint_t thoff)
910{
911 T_TCP_Q_HDR *qhdr;
912 T_NET_BUF **nextp;
913 uint_t inlen, last;
914
915 /* 通信端点をロックする。*/
916 syscall(wai_sem(cep->semid_lock));
917
918 qhdr = (T_TCP_Q_HDR*)GET_TCP_HDR(input, thoff);
919
920 inlen = qhdr->slen;
921
922#ifdef TCP_CFG_RWBUF_CSAVE_MAX_QUEUES
923
924 if (cep->rwbufq_entries >= TCP_CFG_RWBUF_CSAVE_MAX_QUEUES &&
925 inlen > 0 && (qhdr->flags & TCP_FLG_FIN) == 0) {
926
927 /*
928 * TCP 通信端点の受信ウィンドバッファの省コピー機能の、
929 * 受信ウィンドバッファキューの最大エントリ数を超えるときは、
930 * 受信したセグメントを破棄する。
931 * ただし、SDU 長が 0 のセグメントと FIN セグメントは破棄しない。
932 * なお、正常に受信したセグメントも破棄するため、再送回数が増加する。
933 */
934 syscall(rel_net_buf(input));
935
936 /* 通信端点のロックを解除する。*/
937 syscall(sig_sem(cep->semid_lock));
938 return;
939 }
940
941 cep->rwbufq_entries ++;
942
943#endif /* of #ifdef TCP_CFG_RWBUF_CSAVE_MAX_QUEUES */
944
945 qhdr = (T_TCP_Q_HDR*)GET_TCP_HDR(input, thoff);
946
947 /* 受信済みシーケンス番号を更新する。*/
948 cep->rcv_nxt += inlen;
949
950 /* 緊急データの SDU 補正を行う。*/
951 if (qhdr->urp > 0 && inlen > 0) {
952 inlen -= qhdr->urp;
953 qhdr->slen -= qhdr->urp;
954 qhdr->urp = 0;
955 }
956
957 last = cep->rwbuf_count;
958
959 /* ネットワークバッファを受信ウィンドバッファキューの最後に連結する。*/
960 qhdr->next = NULL;
961 nextp = &cep->rwbufq;
962 while (*nextp)
963 nextp = &GET_TCP_Q_HDR(*nextp, GET_TCP_IP_Q_HDR(*nextp)->thoff)->next;
964 *nextp = input;
965
966 /*
967 * FIN フラグが付いたセグメントは inlen == 0 になることもある。
968 * これは、アプリケーションに、相手からこれ以上データが送られて
969 * こないことを知らせるためである。
970 */
971 if (inlen > 0) {
972 cep->rwbuf_count += inlen;
973 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_DATA_SEGS], 1);
974 NET_COUNT_TCP(net_count_tcp[NC_TCP_RECV_DATA_OCTETS], inlen);
975 }
976
977 /* 通信端点のロックを解除する。*/
978 syscall(sig_sem(cep->semid_lock));
979
980#ifdef TCP_CFG_NON_BLOCKING
981
982 if (cep->rcv_nblk_tfn == TFN_TCP_RCV_BUF) { /* ノンブロッキングコール */
983
984 int_t len;
985
986 qhdr = GET_TCP_Q_HDR(cep->rwbufq, GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff);
987 len = qhdr->slen;
988
989 /*
990 * FIN フラグが付いたセグメントは inlen == 0 になることもある。
991 * これは、アプリケーションに、相手からこれ以上データが送られて
992 * こないことを知らせるためである。
993 */
994 if (len > 0 || inlen == 0) {
995
996 /* tcp_rcv_buf の割当て長を設定する。*/
997 cep->rcv_buf_len = len;
998
999 /* 受信ウィンドバッファのアドレスを返す。*/
1000 *cep->rcv_p_buf = GET_TCP_SDU(cep->rwbufq,
1001 GET_TCP_IP_Q_HDR(cep->rwbufq)->thoff) + qhdr->soff;
1002
1003 if (IS_PTR_DEFINED(cep->callback))
1004
1005#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
1006
1007 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)len);
1008
1009#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
1010
1011 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&len);
1012
1013#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
1014
1015 else
1016 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
1017
1018 if (len == 0) {
1019
1020 /*
1021 * 通信端点をロックして、
1022 * 受信ウィンドバッファキューのネットワークバッファを解放する。
1023 */
1024 syscall(wai_sem(cep->semid_lock));
1025 tcp_free_rwbufq_cs(cep);
1026 syscall(sig_sem(cep->semid_lock));
1027 }
1028 }
1029
1030 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
1031 cep->rcv_tskid = TA_NULL;
1032 cep->rcv_tfn = cep->rcv_nblk_tfn = TFN_TCP_UNDEF;
1033 }
1034
1035 else if (cep->rcv_nblk_tfn == TFN_TCP_RCV_DAT) { /* ノンブロッキングコール */
1036 int_t len;
1037
1038 /* 受信ウィンドバッファからデータを取り出す。*/
1039 if ((len = tcp_read_rwbuf_cs(cep, cep->rcv_data, (uint_t)cep->rcv_len)) > 0) {
1040 /* 相手にウィンドウサイズが変わったことを知らせるため出力をポストする。*/
1041 cep->flags |= TCP_CEP_FLG_POST_OUTPUT;
1042 sig_sem(SEM_TCP_POST_OUTPUT);
1043 }
1044
1045 /*
1046 * FIN フラグが付いたセグメントは inlen == 0 になることもある。
1047 * これは、アプリケーションに、相手からこれ以上データが送られて
1048 * こないことを知らせるためである。
1049 */
1050 if (len > 0 || inlen == 0) {
1051
1052 if (IS_PTR_DEFINED(cep->callback))
1053
1054#ifdef TCP_CFG_NON_BLOCKING_COMPAT14
1055
1056 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)len);
1057
1058#else /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
1059
1060 (*cep->callback)(GET_TCP_CEPID(cep), cep->rcv_nblk_tfn, (void*)&len);
1061
1062#endif /* of #ifdef TCP_CFG_NON_BLOCKING_COMPAT14 */
1063
1064 else
1065 syslog(LOG_WARNING, "[TCP] no call back, CEP: %d.", GET_TCP_CEPID(cep));
1066 }
1067
1068 /* 記憶されているタスク ID と API 機能コードをクリアーする。*/
1069 cep->rcv_tskid = TA_NULL;
1070 cep->rcv_tfn = cep->rcv_nblk_tfn = TFN_TCP_UNDEF;
1071 }
1072 else {
1073
1074#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
1075
1076 if (inlen == 0 && cep->rwbuf_count == 0) {
1077 /*
1078 * 受信ウィンドバッファ内のデータ数が 0 で、
1079 * 相手から FIN フラグが付いたセグメントを受信したときは、
1080 * 通信端点をロックして、
1081 * 受信ウィンドバッファキューのネットワークバッファを解放する。
1082 */
1083 syscall(wai_sem(cep->semid_lock));
1084 tcp_free_rwbufq_cs(cep);
1085 syscall(sig_sem(cep->semid_lock));
1086 }
1087
1088 /*
1089 * 受信ウィンドバッファにデータが入るか、 inlen == 0 の時、入力タスクを起床する。
1090 * FIN フラグが付いたセグメントは inlen == 0 になることもある。
1091 * これは、アプリケーションに、相手からこれ以上データが送られて
1092 * こないことを知らせるためである。
1093 */
1094 if ((last == 0 && cep->rwbuf_count > 0) || inlen == 0) {
1095 syscall(set_flg(cep->rcv_flgid, TCP_CEP_EVT_RWBUF_READY));
1096 }
1097
1098#ifdef TCP_CFG_NON_BLOCKING
1099
1100 }
1101
1102#endif /* of #ifdef TCP_CFG_NON_BLOCKING */
1103
1104 }
1105
1106#endif /* of #ifdef TCP_CFG_RWBUF_CSAVE */
1107
1108#endif /* of #ifdef SUPPORT_TCP */
Note: See TracBrowser for help on using the repository browser.