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

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

Azure IoT Hub Device C SDK を使ったサンプルの追加

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