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