1 /*********************************************************************************
3 * --------------------------------------------------------------------------------
5 * This file is part of MiMic
6 * Copyright (C)2011 Ryo Iizuka
8 * MiMic is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * For further information please contact.
23 * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
25 *********************************************************************************/
26 #include "NyLPC_cMiMicIpTcpSocket_protected.h"
27 #include "NyLPC_stdlib.h"
28 #include "NyLPC_cMiMicIpNetIf_protected.h"
31 static NyLPC_TUInt32 iss32=3939;
32 #define SIZE_OF_IPv4_TCPIP_HEADER 40
39 #define UIP_IP_RTO_MAX_RTO 64000
45 #define UIP_TCP_RTO_INITIAL 3000
50 #define UIP_TCP_RTO_CONNECTION_INITIAL 200
55 #define UIP_TCP_RTO_MINIMUM 100
63 NyLPC_TUInt32 rto_log[256];
65 #define DEBUG_RTO_LOG(i_inst) if(rto_log_st<256){rto_log[rto_log_st++]=i_inst->uip_connr.current_rto32;};
67 #define DEBUG_RTO_LOG(i_inst)
70 //#define lockResource(i_inst) NyLPC_cMutex_lock(&((i_inst)->_smutex))
71 //#define unlockResource(i_inst) NyLPC_cMutex_unlock(&((i_inst)->_smutex))
72 #define lockResource(i_inst) NyLPC_cMutex_lock(NyLPC_cIPv4_getSockMutex(((i_inst)->_parent_ipv4)))
73 #define unlockResource(i_inst) NyLPC_cMutex_unlock(NyLPC_cIPv4_getSockMutex(((i_inst)->_parent_ipv4)))
75 static void sendRst(NyLPC_TcMiMicIpTcpSocket_t* i_inst);
80 ////////////////////////////////////////////////////////////////////////////////////////////////////
84 ////////////////////////////////////////////////////////////////////////////////////////////////////
88 * TCPヘッダに値をセットする。checksum,wndは0初期化する。
90 static void setTcpTxHeader(struct NyLPC_TTcpHeader* i_struct,NyLPC_TUInt8 i_flag,const struct uip_conn* i_conn)
92 i_struct->flags = i_flag;
93 //sorce & destination port
94 i_struct->srcport = i_conn->lport;
95 i_struct->destport = i_conn->rport;
97 i_struct->ackno32 = NyLPC_htonl(i_conn->rcv_nxt32);
99 i_struct->seqno32 = NyLPC_htonl(i_conn->snd_nxt32);
100 //uip_func_tcp_send_noconn(BUF);
101 i_struct->urgp[0] = i_struct->urgp[1] = 0;
102 i_struct->tcpchksum= 0;
105 static void setTxPacket(const NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_tx_buf,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len)
107 struct NyLPC_TIPv4Header* iph;
108 struct NyLPC_TTcpHeader* tcph;
109 NyLPC_TUInt8 iph_word=0x05;
110 NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;
112 iph=(struct NyLPC_TIPv4Header*)i_tx_buf;
113 iph->vhl=0x40|(0x0f&iph_word);
114 iph->destipaddr=i_inst->uip_connr.ripaddr;
115 iph->srcipaddr =*(i_inst->uip_connr.lipaddr);
116 NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);
118 tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));
122 if((TCP_SYN & i_tcpf)){
123 tcph_word+=((TCP_OPT_MSS_LEN) / 4);
124 NyLPC_TTcpHeader_setMmsOpt(((NyLPC_TUInt8*)(tcph+1)),i_inst->uip_connr.default_mss);
126 tcph->tcpoffset=(tcph_word<<4);
127 setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr));
129 //最終的なパケットサイズと必要ならペイロードを書き込み
131 iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4);
132 memcpy(((NyLPC_TUInt8*)i_tx_buf)+((iph_word+tcph_word)*4),i_buf,i_len);
134 iph->len16=NyLPC_htons((iph_word+tcph_word)*4);
137 tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));
139 tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
140 iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));
145 * IP/TCPヘッダが40バイト固定として、i_tx_buf+40の位置にあるペイロードに対するIP/TCPヘッダを書き込みます。
147 static void setTxPacketHeader(const NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_tx_buf,NyLPC_TUInt8 i_tcpf,NyLPC_TUInt16 i_len)
149 struct NyLPC_TIPv4Header* iph;
150 struct NyLPC_TTcpHeader* tcph;
151 NyLPC_TUInt8 iph_word=0x05;
152 NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;
154 iph=(struct NyLPC_TIPv4Header*)i_tx_buf;
155 iph->vhl=0x40|(0x0f&iph_word);
156 iph->destipaddr=i_inst->uip_connr.ripaddr;
157 iph->srcipaddr =*(i_inst->uip_connr.lipaddr);
158 NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);
161 tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));
162 tcph->tcpoffset=(tcph_word<<4);
163 setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr));
165 //最終的なパケットサイズと必要ならペイロードを書き込み
166 iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4);
168 tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));
170 tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
171 iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));
179 ////////////////////////////////////////////////////////////////////////////////////////////////////
181 // Mainclass::private
183 ////////////////////////////////////////////////////////////////////////////////////////////////////
190 static void updateAckNo(void* i_tx_buf,NyLPC_TUInt32 i_ackno)
192 struct NyLPC_TIPv4Header* iph=(struct NyLPC_TIPv4Header*)i_tx_buf;
193 struct NyLPC_TTcpHeader* tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));
201 old_ack.l=i_inst->payload.tcp->ackno32;//古いACK番号
202 new_ack.l=i_ackno;//新しいACK番号
203 v1=NyLPC_ntohs(~(i_inst->payload.tcp->tcpchksum));//1の補数を取って、ホストオーダーに戻す。
205 v1=sub16c(v1,(old_ack.b[0]<<8)+old_ack.b[1]);
206 v1=sub16c(v1,(old_ack.b[2]<<8)+old_ack.b[3]);
208 v1=add16c(v1,(new_ack.b[0]<<8)+new_ack.b[1]);
209 v1=add16c(v1,(new_ack.b[2]<<8)+new_ack.b[3]);
210 v1=~NyLPC_htons(v1);*/
212 tcph->ackno32=i_ackno;
216 tcph->tcpchksum = ~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
220 if((i_inst->payload.tcp->tcpchksum!=v1)){
228 * 指定した送信パケットがACK済であるか調べる。
230 static NyLPC_TBool isPacketAcked(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)
233 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
235 while(rp!=i_inst->txbuf.wp){
236 if(q[rp].ackno==i_sq){
237 return NyLPC_TBool_FALSE;
239 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
241 return NyLPC_TBool_TRUE;
244 * 送信キューからi_sq以前に送信したパケットを除外して、残り個数を返却する。
246 static int getNumOfSending(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)
249 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
252 while(rp!=i_inst->txbuf.wp){
253 if(q[rp].ackno==i_sq){
257 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
262 * この関数は、コネクションをリセットします。
264 * 関数は、現在バッファにある再送信待ちデータを開放します。
266 static void resetTxQWithUnlock(NyLPC_TcMiMicIpTcpSocket_t* i_inst)
269 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
270 void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];
273 while(i_inst->txbuf.rp!=i_inst->txbuf.wp){
274 dlist[l]=q[i_inst->txbuf.rp].packet;
276 i_inst->txbuf.rp=(i_inst->txbuf.rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
278 i_inst->txbuf.rp=i_inst->txbuf.wp=0;
280 unlockResource(i_inst);
283 NyLPC_cMiMicIpNetIf_releaseTxBuf(dlist[i]);
288 * TXバッファの再送パケットのACK番号を更新します。
293 static void updateTxAck(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_ackno)
296 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
297 NyLPC_ArgAssert(i_inst!=NULL);
299 while(rp!=i_inst->txbuf.wp){
300 updateAckNo(q[rp].packet,i_ackno);
301 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
308 static void estimateRTO(NyLPC_TcMiMicIpTcpSocket_t* i_inst,int s,int n)
310 NyLPC_TcStopwatch_t sw;
311 NyLPC_TUInt32 cr_rtt_min,cr_rtt_max,sk_rto,new_rto,w;
313 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
314 NyLPC_cStopwatch_initialize(&sw);
316 sk_rto=i_inst->uip_connr.current_rto32;
320 NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);
321 cr_rtt_min=NyLPC_cStopwatch_elapseInMsec(&sw);
322 if(sk_rto<cr_rtt_min){
323 //現在のRTOよりも大きい→再送があった。(再送の理由が回線遅延によるものかわからないので、基本RTOを25%増やす。)
325 }else if(sk_rto/4<cr_rtt_min){
326 //現在のRTOの1/4< n < 現在のRTO 想定内の変動。1/8
327 new_rto=(sk_rto+(cr_rtt_min*3*7))/8;
329 //現在の1/4以下。RTOを再計算。 RTOが大きすぎるので再計算。(計測値を優先した現在値との平均値)
330 new_rto=(sk_rto+(cr_rtt_min*3*3))/4;
334 //複数のパケットなら、最大と最小の時刻を得る。
335 NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);
336 cr_rtt_min=cr_rtt_max=NyLPC_cStopwatch_elapseInMsec(&sw);
338 NyLPC_cStopwatch_set(&sw,q[(s+i)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ].tick_of_sent);
339 w=NyLPC_cStopwatch_elapseInMsec(&sw);
347 if(sk_rto<cr_rtt_min && sk_rto<cr_rtt_max){
348 //最大値,最小値とも現在のRTTより大きい→低速な回線を検出。
349 new_rto=cr_rtt_max*10/8;//最大経過時間の25%増しの時間を設定。
350 }else if(sk_rto/4<cr_rtt_min){
351 //現在のRTOの1/4< n < 現在のRTO 想定範囲内。1/8の加重平均で速度計算。
352 new_rto=(sk_rto+(cr_rtt_min*3*7))/8;
354 //現在の1/4以下。RTOが大きすぎるので再計算。(計測値を優先した加重平均)
355 new_rto=(sk_rto+(cr_rtt_min*3*3))/4;
359 NyLPC_cStopwatch_finalize(&sw);
360 if(new_rto<UIP_TCP_RTO_MINIMUM){
361 new_rto=UIP_TCP_RTO_MINIMUM;
363 i_inst->uip_connr.current_rto32=new_rto;
367 * TXキューから、入力されたシーケンス番号より前のパケットを除外します。
368 * リングバッファのrp->wp-1までをチェックして、sqに等しいi_sq以前のパケットバッファをo_dlistへ返します。
371 static int updateTxQByIndex(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,void* o_dlist[])
374 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
379 DEBUG_RTO_LOG(i_inst);
381 while(rp!=i_inst->txbuf.wp){
382 o_dlist[n]=q[rp].packet;
383 if(q[rp].ackno==i_sq){
384 //i_inst->txbuf.rp->rpのパケットのRTOからbaseRTOの値を再計算。
385 estimateRTO(i_inst,i_inst->txbuf.rp,n+1);
386 i_inst->txbuf.rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
390 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
401 static struct NyLPC_TcTcpSocket_TxQItem* getTxQ(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TcStopwatch_t* i_timer)
404 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
406 //クローズドに遷移してしまったら、エラーである。
407 if(i_inst->tcpstateflags==UIP_CLOSED){
410 //キューの空きをチェック。wp+1==rpなら、キューがいっぱい。rp==wpなら、キューが空。
411 if(((i_inst->txbuf.wp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ)==i_inst->txbuf.rp){
413 unlockResource(i_inst);
415 NyLPC_cThread_yield();
417 lockResource(i_inst);
421 i_inst->txbuf.wp=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
423 }while(!NyLPC_cStopwatch_isExpired(i_timer));
433 /**********************************************************************
435 **********************************************************************/
436 static const struct NyLPC_TIPv4Addr* getPeerAddr(const NyLPC_TiTcpSocket_t* i_inst);
437 static NyLPC_TUInt16 getPeerPort(const NyLPC_TiTcpSocket_t* i_inst);
438 static NyLPC_TBool accept(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec);
439 static NyLPC_TInt32 precv(NyLPC_TiTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec);
440 static void pseek(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek);
441 static NyLPC_TInt32 send(NyLPC_TiTcpSocket_t* i_inst,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec);
442 static void close(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec);
443 static void* allocSendBuf(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec);
444 static void releaseSendBuf(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr);
445 static NyLPC_TBool psend(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec);
446 static NyLPC_TBool connect(NyLPC_TiTcpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_peer_port,NyLPC_TUInt32 i_wait_in_msec);
447 static void finalize(NyLPC_TiTcpSocket_t* i_inst);
449 const static struct NyLPC_TiTcpSocket_Interface _interface=
465 static const struct NyLPC_TIPv4Addr* getPeerAddr(const NyLPC_TiTcpSocket_t* i_inst)
467 const NyLPC_TcMiMicIpTcpSocket_t* inst=(const NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
468 return &inst->uip_connr.ripaddr;
470 static NyLPC_TUInt16 getPeerPort(const NyLPC_TiTcpSocket_t* i_inst)
472 const NyLPC_TcMiMicIpTcpSocket_t* inst=(const NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
473 return inst->uip_connr.rport;
479 NyLPC_TBool NyLPC_cMiMicIpTcpSocket_initialize(NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)
482 NyLPC_TcMiMicIpNetIf_t* srv=_NyLPC_TcMiMicIpNetIf_inst;
483 i_inst->_super._interface=&_interface;
484 i_inst->_parent_ipv4=&srv->_tcpv4;
487 NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
489 NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len);
490 // NyLPC_AbortIfNot(NyLPC_cMutex_initialize(&(i_inst->_smutex)));//個別Mutex
491 // i_inst->_smutex=NyLPC_cIPv4_getSockMutex(&(srv->_tcpv4));//共有Mutex
492 i_inst->tcpstateflags=UIP_CLOSED;
493 i_inst->txbuf.rp=i_inst->txbuf.wp=0;
494 for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){
495 i_inst->txbuf.txq[i].packet=NULL;
498 return NyLPC_TBool_TRUE;
503 NyLPC_TBool NyLPC_cMiMicIpTcpSocket_listenSyn(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const struct NyLPC_TTcpSocketSynParam* i_lq,NyLPC_TUInt16 i_lport)
505 // NyLPC_Assert(NyLPC_cMutex_isLocked(i_inst->_smutex));
506 lockResource(i_inst);
508 if(i_inst->tcpstateflags==UIP_CLOSED)
510 //localipとdefault_mmsは別枠で設定
511 /* Fill in the necessary fields for the new connection. */
512 i_inst->uip_connr.current_rto32 = UIP_TCP_RTO_INITIAL;
513 i_inst->uip_connr.lport = i_lport;
514 i_inst->uip_connr.rport = i_lq->rport;
515 i_inst->uip_connr.ripaddr=i_lq->srcaddr;
516 i_inst->uip_connr.snd_nxt32=iss32;
517 /* rcv_nxt should be the seqno from the incoming packet + 1. */
518 i_inst->uip_connr.rcv_nxt32= i_lq->rcv_nxt32;
520 i_inst->uip_connr.peer_mss=(i_lq->mss!=0)?i_lq->mss:i_inst->uip_connr.default_mss;
521 i_inst->uip_connr.peer_win=0;
522 NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
524 i_inst->tcpstateflags = UIP_SYN_RCVD;
526 if(i_inst->txbuf.rp!=i_inst->txbuf.wp){
527 resetTxQWithUnlock(i_inst);
529 unlockResource(i_inst);
531 return NyLPC_TBool_TRUE;
533 unlockResource(i_inst);
534 return NyLPC_TBool_FALSE;
539 * sq番のTxがキューから消え去るのを待ちます。
540 * この関数は、アンロック状態でコールしてください。
542 * パケットがキューからなくなる条件は、以下の2つです。
544 * <li>ACKを受信してパケットキューが更新された。</li>
545 * <li>RSTを受信して(CLOSEDに遷移して)、キューがクリアされた。</li>
546 * <li>送信タイムアウトで関数が(CLOSEDに遷移させて)キューをクリアした。</li>
551 * 1番目の条件でパケットが消失したときのみ、TRUEを返します。
552 * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。
554 static NyLPC_TBool waitForTxRemove(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,NyLPC_TcStopwatch_t* i_timer)
557 lockResource(i_inst);
560 if(!isPacketAcked(i_inst,i_sq)){
561 //まだある場合は、タスクスイッチを繰り返して消失を待つ。
562 unlockResource(i_inst);
563 NyLPC_cThread_yield();
564 lockResource(i_inst);
568 f=i_inst->tcpstateflags;
569 unlockResource(i_inst);
570 return (f==UIP_CLOSED)?NyLPC_TBool_FALSE:NyLPC_TBool_TRUE;
571 }while(!NyLPC_cStopwatch_isExpired(i_timer));
572 unlockResource(i_inst);
573 return NyLPC_TBool_FALSE;
578 * 再送信処理をセットして、パケットを送信します。
579 * この関数は「アンロック状態で」実行してください。
582 * この番号は、シーケンス番号の加算値ではありませんので、注意をしてください。
585 * <li>n=-1:送信キューへの投入に失敗した。</li>
586 * <li>n>=0:nバイトのデータを送信キューへの投入することに成功した。</li>
588 * 送信キューに失敗する理由は2つあります。1つは、TXバッファがフルでタイムアウト。もうひとつは、非同期なコネクリョンのリセットです。
589 * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。
591 static NyLPC_TInt32 sendWithRetransmit(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len,NyLPC_TcStopwatch_t* i_timer,NyLPC_TUInt32* o_ack)
593 struct NyLPC_TcTcpSocket_TxQItem* txq;
596 NyLPC_TUInt32 next_ack;
598 //@bug オブションパケット送信時に4バイト足りないメモリ要求しない?問題になってないけど。
600 buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_len+(SIZE_OF_IPv4_TCPIP_HEADER),&s);
605 if(NyLPC_cStopwatch_isExpired(i_timer)){
609 lockResource(i_inst);
610 //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。
612 while(i_inst->uip_connr.peer_win==0){
613 unlockResource(i_inst);
615 if(NyLPC_cStopwatch_isExpired(i_timer)){
618 NyLPC_cThread_yield();
619 lockResource(i_inst);
623 txq=getTxQ(i_inst,i_timer);
626 //シーケンス番号をロールバックできないので、エラーとする。
627 unlockResource(i_inst);
628 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
632 //送信バッファを基準とした送信サイズを計算
633 s-=SIZE_OF_IPv4_TCPIP_HEADER;
634 //送信サイズよりMMSが小さければ、送信サイズを修正
635 if(i_inst->uip_connr.peer_mss<s){
636 s=i_inst->uip_connr.peer_mss;
638 //送信サイズよりpeerのウインドウサイズが小さければ修正
639 if(i_inst->uip_connr.peer_win<s){
640 s=i_inst->uip_connr.peer_win;
642 //送信サイズより、データサイズが小さければ、送信サイズを修正
647 next_ack=i_inst->uip_connr.snd_nxt32+s+(((i_tcpf&(TCP_FIN|TCP_SYN))!=0x00)?1:0);
648 txq->rto32=i_inst->uip_connr.current_rto32;
649 txq->tick_of_sent=NyLPC_cStopwatch_now();
652 setTxPacket(i_inst,buf,i_tcpf,i_buf,s);
656 i_inst->uip_connr.snd_nxt32=next_ack;
658 i_inst->uip_connr.peer_win-=s;
660 *o_ack=txq->ackno=NyLPC_HTONL(next_ack);
661 unlockResource(i_inst);
662 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
667 * この関数は、クローズドステータスのソケットにしてからコールします。
668 * この関数は、アンロック状態でコールしてね。
670 static void sendRst(NyLPC_TcMiMicIpTcpSocket_t* i_inst)
674 NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);
677 //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。
678 buf=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
679 lockResource(i_inst);
680 i_inst->uip_connr.snd_nxt32++;
681 unlockResource(i_inst);
682 setTxPacket(i_inst,buf,TCP_RST|TCP_ACK,NULL,0);
683 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
684 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
685 NyLPC_cIPv4Payload_finalize(&ipv4);
694 * この関数は、ロックして実行してください。
696 static NyLPC_TBool addRecvData(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const void* i_data,NyLPC_TUInt16 i_data_size)
699 if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))>=i_data_size){
701 NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),i_data,i_data_size);
704 return NyLPC_TBool_FALSE;
707 return NyLPC_TBool_TRUE;
717 static void finalize(NyLPC_TiTcpSocket_t* i_inst)
720 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
721 NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
723 if(inst->txbuf.rp!=inst->txbuf.wp){
725 resetTxQWithUnlock(inst);
727 for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){
728 inst->txbuf.txq[i].packet=NULL;
730 NyLPC_cFifoBuffer_finalize(&(inst->rxbuf));
731 // NyLPC_cMutex_finalize(&(i_inst->_smutex));
732 NyLPC_cMiMicIpNetIf_releaseTcpSocketMemory(inst);
737 static NyLPC_TBool connect(NyLPC_TiTcpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_peer_port,NyLPC_TUInt32 i_wait_in_msec)
739 volatile NyLPC_TUInt8 f;
740 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
742 NyLPC_TcStopwatch_t sw;
746 if(inst->tcpstateflags!=UIP_CLOSED)
748 NyLPC_OnErrorGoto(Error);
750 //ポート番号の取得(lockResourceが他のソケットと共有なので、重複ポートの割当は起こりえない。でもちょっと注意して)
751 lport=NyLPC_htons(NyLPC_cIPv4_getNewPortNumber(inst->_parent_ipv4));
753 NyLPC_OnErrorGoto(Error);
757 //localipとdefault_mmsは別枠で設定
758 /* Fill in the necessary fields for the new connection. */
759 inst->uip_connr.current_rto32 = UIP_TCP_RTO_CONNECTION_INITIAL;//RTOを短くしてARP発行時の再接続短縮を期待する。
760 inst->uip_connr.lport = lport;
761 inst->uip_connr.rport = NyLPC_htons(i_peer_port);
762 inst->uip_connr.ripaddr=*i_addr;
763 inst->uip_connr.snd_nxt32=iss32;//should be random
764 /* rcv_nxt should be the seqno from the incoming packet + 1. */
765 inst->uip_connr.rcv_nxt32=0;
767 inst->uip_connr.peer_mss=inst->uip_connr.default_mss;
768 inst->uip_connr.peer_win=1;//periodicの再送信を期待するために相手のWindowサイズは1と仮定する。
769 NyLPC_cFifoBuffer_clear(&(inst->rxbuf));
771 inst->tcpstateflags = UIP_SYN_SENT;
773 if(inst->txbuf.rp!=inst->txbuf.wp){
774 resetTxQWithUnlock(inst);
776 unlockResource(inst);
779 NyLPC_cStopwatch_initialize(&sw);
781 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
782 if(sendWithRetransmit(inst,TCP_SYN,NULL,0,&sw,&sq)==0){
784 NyLPC_cThread_yield();
786 if(waitForTxRemove(inst,sq,&sw)){
788 NyLPC_cStopwatch_finalize(&sw);
789 return NyLPC_TBool_TRUE;
794 f=inst->tcpstateflags;
796 //もし、強制CLOSE遷移であれば、RSTも送信。
797 inst->tcpstateflags=UIP_CLOSED;
798 unlockResource(inst);
801 unlockResource(inst);
803 return NyLPC_TBool_FALSE;
805 unlockResource(inst);
806 return NyLPC_TBool_FALSE;
810 * この関数は、UIP_SYN_RCVDステータスのソケットを、ESTABLISHEDへ遷移させます。
811 * cTcpListener_listen関数を通過したインスタンスに実行してください。
812 * この関数は、アプリケーションが呼び出します。
816 static NyLPC_TBool accept(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)
818 volatile NyLPC_TUInt8 f;
819 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
821 NyLPC_TcStopwatch_t sw;
823 NyLPC_cStopwatch_initialize(&sw);
825 f=inst->tcpstateflags;
828 case UIP_ESTABLISHED:
829 return NyLPC_TBool_TRUE;
834 return NyLPC_TBool_FALSE;
836 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
837 if(sendWithRetransmit(inst,TCP_SYN|TCP_ACK,NULL,0,&sw,&sq)==0){
839 NyLPC_cThread_yield();
841 if(waitForTxRemove(inst,sq,&sw)){
843 NyLPC_cStopwatch_finalize(&sw);
844 return NyLPC_TBool_TRUE;
849 f=inst->tcpstateflags;
851 //もし、強制CLOSE遷移であれば、RSTも送信。
852 inst->tcpstateflags=UIP_CLOSED;
853 unlockResource(inst);
856 unlockResource(inst);
858 return NyLPC_TBool_FALSE;
863 * この関数は、ソケットの受信バッファの読み取り位置と、読み出せるデータサイズを返却します。
864 * 関数はポインターを返却するだけで、バッファの読み取り位置をシークしません。
865 * シークするにはNyLPC_cTcpSocket_pseekを使います。
867 static NyLPC_TInt32 precv(NyLPC_TiTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec)
869 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
870 volatile NyLPC_TUInt8 st;
873 NyLPC_TcStopwatch_t sw;
874 NyLPC_cStopwatch_initialize(&sw);
876 //ESTABLISHED以外の場合は、エラー。
877 NyLPC_cStopwatch_setNow(&sw);
882 st=inst->tcpstateflags;
883 rlen=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
884 *o_buf_ptr=NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
886 unlockResource(inst);
888 //バッファが空の場合は、ステータスチェック。ESTABLISHEDでなければ、エラー(PASVCLOSE等の場合)
890 case UIP_ESTABLISHED:
893 NyLPC_cStopwatch_finalize(&sw);
900 NyLPC_cStopwatch_finalize(&sw);
906 NyLPC_cStopwatch_finalize(&sw);
910 NyLPC_cThread_yield();
911 }while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec);
913 NyLPC_cStopwatch_finalize(&sw);
920 static void pseek(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek)
923 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
925 NyLPC_ArgAssert(i_seek<=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf)));
931 buf=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
937 NyLPC_cFifoBuffer_pop(&(inst->rxbuf),i_seek);
939 setTxPacket(inst,buf,TCP_ACK,NULL,0);
940 unlockResource(inst);
942 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
943 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
950 static void* allocSendBuf(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec)
952 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
956 NyLPC_TcStopwatch_t sw;
958 NyLPC_cStopwatch_initialize(&sw);
959 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
962 //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。
964 //ESTABLISHED以外に非同期遷移
965 if(inst->tcpstateflags!=UIP_ESTABLISHED){
966 NyLPC_cStopwatch_finalize(&sw);
969 buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_hint+(SIZE_OF_IPv4_TCPIP_HEADER),&s);
974 if(NyLPC_cStopwatch_isExpired(&sw)){
975 NyLPC_cStopwatch_finalize(&sw);
980 //@todo 前段処理と順番を入れ替えて、要求サイズとpeerのwinのうち、小さいほうを割り当てたほうが良くない?
981 //ここで相手のwin待ちをする理由は、相手に確実に受け取れるサイズを決定する為。
983 //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。
984 while(inst->uip_connr.peer_win==0){
985 unlockResource(inst);
986 //ESTABLISHED以外に非同期遷移 orタイムアウト確認
987 if(NyLPC_cStopwatch_isExpired(&sw)||(inst->tcpstateflags!=UIP_ESTABLISHED)){
988 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
989 NyLPC_cStopwatch_finalize(&sw);
992 NyLPC_cThread_yield();
995 //送信バッファを基準とした送信サイズを計算
996 s-=SIZE_OF_IPv4_TCPIP_HEADER;
997 //送信サイズよりMMSが小さければ、送信サイズを修正
998 if(inst->uip_connr.peer_mss<s){
999 s=inst->uip_connr.peer_mss;
1001 //送信サイズよりpeerのウインドウサイズが小さければ修正
1002 if(inst->uip_connr.peer_win<s){
1003 s=inst->uip_connr.peer_win;
1005 unlockResource(inst);
1008 NyLPC_cStopwatch_finalize(&sw);
1009 return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_TCPIP_HEADER;
1014 static void releaseSendBuf(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr)
1016 NyLPC_cMiMicIpNetIf_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER);
1021 * 事前にAllocしたTxパケットを送信します。
1022 * このAPIはゼロコピー送信をサポートするためのものです。
1024 * allocSendBufで取得したメモリを指定します。
1026 * 関数が失敗した場合、i_buf_ptrは「開放されません。」
1028 static NyLPC_TBool psend(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec)
1030 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
1031 struct NyLPC_TcTcpSocket_TxQItem* txq;
1033 NyLPC_TcStopwatch_t sw;
1034 //ESTABLISHEDでなければエラー
1035 if(inst->tcpstateflags!=UIP_ESTABLISHED){
1036 //ESTABLISHEDでなければエラー
1037 return NyLPC_TBool_FALSE;
1041 releaseSendBuf(i_inst,i_buf_ptr);
1042 return NyLPC_TBool_TRUE;
1044 NyLPC_cStopwatch_initialize(&sw);
1045 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
1047 //先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定
1048 buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER;
1051 txq=getTxQ(inst,&sw);
1054 //シーケンス番号をロールバックできないので、エラーとする。
1055 unlockResource(inst);
1056 NyLPC_cStopwatch_finalize(&sw);
1057 return NyLPC_TBool_FALSE;
1059 //ここから先はi_bufの所有権はインスタンスになってる。
1063 //allocをした時点でwin,mssは考慮されているので、そのままそうしんしる。
1066 txq->rto32=inst->uip_connr.current_rto32;
1067 txq->tick_of_sent=NyLPC_cStopwatch_now();
1068 //パケットヘッダの生成(ヘッダ長はpreadで定義した値(4+6)*4=40です。)
1069 setTxPacketHeader(inst,buf,TCP_ACK|TCP_PSH,i_len);
1073 inst->uip_connr.snd_nxt32=inst->uip_connr.snd_nxt32+i_len;
1075 inst->uip_connr.peer_win-=i_len;
1077 txq->ackno=NyLPC_HTONL(inst->uip_connr.snd_nxt32);
1078 unlockResource(inst);
1079 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
1080 NyLPC_cStopwatch_finalize(&sw);
1081 return NyLPC_TBool_TRUE;
1087 static NyLPC_TInt32 send(NyLPC_TiTcpSocket_t* i_inst,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec)
1095 hint=(i_len>32767)?32767:i_len;
1096 buf=allocSendBuf(i_inst,hint,&s,i_wait_in_msec);
1101 s=((NyLPC_TInt32)s<i_len)?s:(NyLPC_TUInt16)i_len;
1102 memcpy(buf,i_buf_ptr,s);
1103 if(!psend(i_inst,buf,s,i_wait_in_msec)){
1104 releaseSendBuf(i_inst,buf);
1111 static void close(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)
1113 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
1114 NyLPC_TcStopwatch_t sw;
1115 volatile NyLPC_TUInt8 f;
1117 NyLPC_cStopwatch_initialize(&sw);
1118 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
1121 f=inst->tcpstateflags;
1127 goto ReturnWithUnlock;
1128 case UIP_ESTABLISHED:
1130 inst->tcpstateflags=UIP_FIN_WAIT_1;
1132 unlockResource(inst);
1134 if(sendWithRetransmit(inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){
1136 NyLPC_cThread_yield();
1138 if(waitForTxRemove(inst,sq,&sw)){
1141 //タイムアウトするか、UIP_CLOSED、もしくはTIME_WAITに遷移するのを待つ。(遷移はRxprocで自動的に実行。)
1143 switch(inst->tcpstateflags)
1146 inst->tcpstateflags=UIP_CLOSED;
1148 NyLPC_Assert(inst->txbuf.rp==inst->txbuf.wp);
1150 goto ReturnWithUnlock;
1151 case UIP_FIN_WAIT_1:
1152 case UIP_FIN_WAIT_2:
1155 unlockResource(inst);
1156 NyLPC_cThread_yield();
1161 }while(!NyLPC_cStopwatch_isExpired(&sw));
1162 unlockResource(inst);
1166 case UIP_CLOSE_WAIT:
1168 inst->tcpstateflags=UIP_LAST_ACK;
1170 unlockResource(inst);
1171 if(sendWithRetransmit(inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){
1173 NyLPC_cThread_yield();
1175 if(waitForTxRemove(inst,sq,&sw)){
1178 //TX消去後にCLOSEDに遷移していればOK
1179 if(inst->tcpstateflags==UIP_CLOSED)
1181 NyLPC_Assert(inst->txbuf.rp==inst->txbuf.wp);
1182 goto ReturnWithUnlock;
1184 unlockResource(inst);
1190 unlockResource(inst);
1194 // if(i_inst->_smutex._lock_count>0){
1197 //このパスに到達するのは、FIN送信/ACKに成功したにも拘らず、規定時間内にCLOSEDに遷移しなかった場合。
1200 f=inst->tcpstateflags;
1202 //もし、強制CLOSE遷移であれば、RSTも送信。
1203 inst->tcpstateflags=UIP_CLOSED;
1204 unlockResource(inst);
1207 unlockResource(inst);
1209 NyLPC_cStopwatch_finalize(&sw);
1212 unlockResource(inst);
1213 NyLPC_cStopwatch_finalize(&sw);
1218 * uipサービスタスクが実行する関数です。
1219 * 定期的に実行する関数。最低でも1s単位で実行してください。
1221 void NyLPC_cMiMicIpTcpSocket_periodic(
1222 NyLPC_TcMiMicIpTcpSocket_t* i_inst)
1225 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
1226 NyLPC_TcStopwatch_t sw;
1229 NyLPC_cStopwatch_initialize(&sw);
1230 now=NyLPC_cStopwatch_now();
1232 lockResource(i_inst);
1233 if(i_inst->tcpstateflags==UIP_CLOSED)
1236 resetTxQWithUnlock(i_inst);
1237 }else if(i_inst->txbuf.rp==i_inst->txbuf.wp){
1238 //再送信パケットがなければ何もしないよ。
1239 unlockResource(i_inst);
1240 }else if(i_inst->uip_connr.peer_win==0){
1241 //peer_winが0の場合は何もしない。
1242 unlockResource(i_inst);
1245 rp=i_inst->txbuf.rp;
1246 NyLPC_cStopwatch_set(&sw,q[rp].tick_of_sent);
1247 if(NyLPC_cStopwatch_elapseInMsec(&sw)>q[rp].rto32){
1248 //最古のパケットの送信時間をチェックして、タイムアウトが発生したら、再送時間と送信時刻をセット
1251 for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){
1252 q[i].tick_of_sent=now;
1254 if(q[rp].rto32>UIP_IP_RTO_MAX_RTO){
1255 //最古のRTOが64秒を超えたら、CLOSED
1256 i_inst->tcpstateflags =UIP_CLOSED;
1257 resetTxQWithUnlock(i_inst);
1261 for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){
1262 // NyLPC_cUipService_sendIPv4Tx(NyLPC_cIPv4Payload_getBuf(&(q[i].data)));
1263 NyLPC_cMiMicIpNetIf_sendIPv4Tx(q[i].packet);
1265 unlockResource(i_inst);
1268 unlockResource(i_inst);
1271 NyLPC_cStopwatch_finalize(&sw);
1275 * uipサービスタスクが実行する関数です。
1278 void NyLPC_cMiMicIpTcpSocket_startService(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config)
1280 NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);//閉じてなければおかしい。
1281 i_inst->uip_connr.lipaddr=&(i_config->ip_addr);
1282 i_inst->uip_connr.default_mss=i_config->default_mss;
1283 //NyLPC_cTcpSocket_setSynPayload関数でも実行するけど、IFのリセット時なのでここでもやる。
1284 NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
1288 * uipサービスタスクが実行する関数です。
1291 void NyLPC_cMiMicIpTcpSocket_stopService(NyLPC_TcMiMicIpTcpSocket_t* i_inst)
1293 lockResource(i_inst);
1294 if(i_inst->tcpstateflags==UIP_CLOSED)
1296 unlockResource(i_inst);
1298 i_inst->tcpstateflags=UIP_CLOSED;
1299 resetTxQWithUnlock(i_inst);
1306 void* NyLPC_cMiMicIpTcpSocket_parseRx(
1307 NyLPC_TcMiMicIpTcpSocket_t* i_inst,
1308 const NyLPC_TcIPv4Payload_t* i_ipp)
1311 NyLPC_TUInt16 tmp16;
1312 NyLPC_TUInt16 data_size;
1313 NyLPC_TUInt8 in_tcpflag=i_ipp->payload.tcp->flags;
1314 const void* tcp_data_offset;
1315 NyLPC_TBool is_new_packet;
1317 void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];
1322 tmp16=NyLPC_TTcpHeader_getHeaderLength(i_ipp->payload.tcp);
1323 //TCPペイロードの長さは、IPパケットの長さ-(IPヘッダ+TCPヘッダ)
1324 data_size=NyLPC_TIPv4Header_getPacketLength(i_ipp->header)-NyLPC_TIPv4Header_getHeaderLength(i_ipp->header)-tmp16;
1326 tcp_data_offset=i_ipp->payload.rawbuf+tmp16;
1329 lockResource(i_inst);
1331 //RSTのチェック。RST受信時は、状態にかかわらず、CLOSEDステータスに移行する。
1332 if (in_tcpflag & TCP_RST)
1334 i_inst->tcpstateflags =UIP_CLOSED;
1339 is_new_packet=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)==i_inst->uip_connr.rcv_nxt32;
1345 if(NyLPC_TTcpHeader_getTcpMmsOpt(i_ipp->payload.tcp,&tmp16)){
1347 i_inst->uip_connr.peer_mss=tmp16;
1349 //受信パケットを元に、未ACKパケットの数を計算
1350 num_of_noack=getNumOfSending(i_inst,i_ipp->payload.tcp->ackno32);//i_inst->txbuf.num_of_txq;
1353 switch(i_inst->tcpstateflags)
1356 //ACKを受信したら、ESTABLISHEDへ。
1357 //すべてのパケットをACKしたかで判定。()
1358 if(num_of_noack==0){
1359 i_inst->tcpstateflags=UIP_ESTABLISHED;
1368 //引き続き、ESTABLISHEDの処理へ。
1369 case UIP_ESTABLISHED:
1372 if(addRecvData(i_inst,tcp_data_offset,data_size)){
1374 i_inst->uip_connr.rcv_nxt32+=data_size;
1376 //失敗したときは必要に応じて単純ACK
1381 if(is_new_packet && (in_tcpflag & TCP_FIN)){
1382 //FINがあるときは、ステータスをCLOSE_WAITへセットして、ACKを返す。
1383 i_inst->tcpstateflags = UIP_CLOSE_WAIT;
1384 i_inst->uip_connr.rcv_nxt32++;
1387 case UIP_CLOSE_WAIT:
1391 //ACK(by FIN)が得られたなら、CLOSEDへ。
1392 if(num_of_noack==0){
1393 i_inst->tcpstateflags=UIP_CLOSED;
1397 case UIP_FIN_WAIT_1:
1400 i_inst->uip_connr.rcv_nxt32+=data_size;
1401 if(in_tcpflag & TCP_FIN){
1402 i_inst->uip_connr.rcv_nxt32++;
1403 if(num_of_noack==0){
1405 i_inst->tcpstateflags=UIP_TIME_WAIT;
1408 i_inst->tcpstateflags=UIP_CLOSING;
1411 }else if(num_of_noack==0){
1413 i_inst->tcpstateflags=UIP_FIN_WAIT_2;
1417 case UIP_FIN_WAIT_2:
1418 //FIN受信->TIME_WAITへ(pureACK)
1419 if(is_new_packet && (in_tcpflag & TCP_FIN)){
1420 i_inst->uip_connr.rcv_nxt32++;
1421 i_inst->tcpstateflags=UIP_TIME_WAIT;
1425 //ACK受信したら、TIME_WAITへ
1426 if(num_of_noack==0){
1427 i_inst->tcpstateflags=UIP_TIME_WAIT;
1437 //connect関数実行中しか起動しないステータス
1438 if(num_of_noack==0){
1439 i_inst->tcpstateflags=UIP_ESTABLISHED;
1440 i_inst->uip_connr.rcv_nxt32=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)+1;
1451 i_inst->uip_connr.peer_win=NyLPC_ntohs(i_ipp->payload.tcp->wnd16);
1453 //送信キューから、Peerが受信したデータを削除する。
1454 if(in_tcpflag & TCP_ACK){
1455 //再送パケットキューから送信済みのデータを回収(後で開放)
1457 s=updateTxQByIndex(i_inst,i_ipp->payload.tcp->ackno32,dlist);
1462 //新しいパケットがきた場合は、再送キューのACKを更新する。
1465 updateTxAck(i_inst,NyLPC_htonl(i_inst->uip_connr.rcv_nxt32));
1469 if(((in_tcpflag&(TCP_FIN|TCP_SYN))!=0x00) ||
1470 ((!is_new_packet) && (data_size>0)))
1472 //ソケットからPureACKを生成 as setPacket(i_inst,i_ipp,TCP_ACK,NULL,0);
1473 ret=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
1474 setTxPacket(i_inst,ret,TCP_ACK,NULL,0);
1478 unlockResource(i_inst);
1482 NyLPC_cMiMicIpNetIf_releaseTxBuf(dlist[i]);
1487 //ACKしたパケットを送信キューから削除
1488 unlockResource(i_inst);
1495 * 入力されたパケットからRSTパケットを生成して返す。
1497 void* NyLPC_cMiMicIpTcpSocket_allocTcpReverseRstAck(
1498 const NyLPC_TcIPv4Payload_t* i_src)
1500 struct NyLPC_TIPv4Header* iph;
1501 struct NyLPC_TTcpHeader* tcph;
1502 NyLPC_TUInt8 iph_word=0x05;
1503 NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;
1504 void* txb=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
1506 iph=(struct NyLPC_TIPv4Header*)txb;
1507 iph->vhl=0x40|(0x0f&iph_word);
1508 iph->destipaddr=i_src->header->srcipaddr;
1509 iph->srcipaddr =i_src->header->destipaddr;
1510 NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);
1513 tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)txb)+NyLPC_TIPv4Header_getHeaderLength(iph));
1515 tcph->tcpoffset=(tcph_word<<4);
1517 tcph->flags = TCP_RST | TCP_ACK;
1518 //sorce & destination port
1519 tcph->srcport = i_src->payload.tcp->destport;
1520 tcph->destport = i_src->payload.tcp->srcport;
1522 tcph->ackno32 = NyLPC_htonl(NyLPC_ntohl(i_src->payload.tcp->seqno32)+1);
1524 tcph->seqno32 = i_src->payload.tcp->ackno32;
1525 //uip_func_tcp_send_noconn(BUF);
1526 tcph->urgp[0] = tcph->urgp[1] = 0;
1530 //最終的なパケットサイズと必要ならペイロードを書き込み
1531 iph->len16=NyLPC_htons((iph_word+tcph_word)*4);
1535 tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
1536 iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));