source: azure_iot_hub/trunk/asp3_dcre/tinet/netinet/tcp_subr_cs.c@ 389

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

ビルドが通るよう更新

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