OSDN Git Service

add mbed.html
[mimic/MiMicSDK.git] / lib / src / uip / NyLPC_cTcpSocket.c
1 /*********************************************************************************\r
2  * PROJECT: MiMic\r
3  * --------------------------------------------------------------------------------\r
4  *\r
5  * This file is part of MiMic\r
6  * Copyright (C)2011 Ryo Iizuka\r
7  *\r
8  * MiMic is free software: you can redistribute it and/or modify\r
9  * it under the terms of the GNU Lesser General Public License as published\r
10  * by the Free Software Foundation, either version 3 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU Lesser General Public License\r
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
20  *\r
21  * For further information please contact.\r
22  *      http://nyatla.jp/\r
23  *      <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
24  *\r
25  *********************************************************************************/\r
26 #include "NyLPC_cTcpSocket_protected.h"\r
27 #include "NyLPC_stdlib.h"\r
28 #include "NyLPC_cUipService_protected.h"\r
29 \r
30 \r
31 static NyLPC_TUInt32 iss32=3939;\r
32 #define SIZE_OF_IPv4_TCPIP_HEADER 40\r
33 \r
34 /**\r
35  * TCPのRTOの最大値。\r
36  * ms単位である。\r
37  * defaultは64SEC\r
38  */\r
39 #define UIP_IP_RTO_MAX_RTO 64000\r
40 /**\r
41  * TCPのRTOの初期値。\r
42  * ms単位である。\r
43  * 伝送路の特性に合わせて調整すること。\r
44  */\r
45 #define UIP_TCP_RTO_INITIAL 3000\r
46 \r
47 /**\r
48  * CONNECTION時のRTO\r
49  */\r
50 #define UIP_TCP_RTO_CONNECTION_INITIAL 200\r
51 \r
52 /**\r
53  * 下限値\r
54  */\r
55 #define UIP_TCP_RTO_MINIMUM 100\r
56 \r
57 \r
58 /**\r
59  * for Debug\r
60  * RTOの情報をログ領域に取る。\r
61  */\r
62 #ifdef RTO_LOG\r
63         NyLPC_TUInt32 rto_log[256];\r
64         int rto_log_st=0;\r
65         #define DEBUG_RTO_LOG(i_inst) if(rto_log_st<256){rto_log[rto_log_st++]=i_inst->uip_connr.current_rto32;};\r
66 #else\r
67         #define DEBUG_RTO_LOG(i_inst)\r
68 #endif\r
69 \r
70 //#define lockResource(i_inst) NyLPC_cMutex_lock(&((i_inst)->_smutex))\r
71 //#define unlockResource(i_inst) NyLPC_cMutex_unlock(&((i_inst)->_smutex))\r
72 #define lockResource(i_inst) NyLPC_cMutex_lock(NyLPC_cIPv4_getSockMutex(((i_inst)->_super._parent_ipv4)))\r
73 #define unlockResource(i_inst) NyLPC_cMutex_unlock(NyLPC_cIPv4_getSockMutex(((i_inst)->_super._parent_ipv4)))\r
74 \r
75 static void sendRst(NyLPC_TcTcpSocket_t* i_inst);\r
76 \r
77 \r
78 \r
79 \r
80 ////////////////////////////////////////////////////////////////////////////////////////////////////\r
81 //\r
82 //      Packet writer\r
83 //\r
84 ////////////////////////////////////////////////////////////////////////////////////////////////////\r
85 \r
86 \r
87 /**\r
88  * TCPヘッダに値をセットする。checksum,wndは0初期化する。\r
89  */\r
90 static void setTcpTxHeader(struct NyLPC_TTcpHeader* i_struct,NyLPC_TUInt8 i_flag,const struct uip_conn* i_conn)\r
91 {\r
92         i_struct->flags    = i_flag;\r
93         //sorce & destination port\r
94         i_struct->srcport  = i_conn->lport;\r
95         i_struct->destport = i_conn->rport;\r
96         //ACK number\r
97         i_struct->ackno32  = NyLPC_htonl(i_conn->rcv_nxt32);\r
98         //Seq Number\r
99         i_struct->seqno32  = NyLPC_htonl(i_conn->snd_nxt32);\r
100         //uip_func_tcp_send_noconn(BUF);\r
101         i_struct->urgp[0]  = i_struct->urgp[1] = 0;\r
102         i_struct->tcpchksum= 0;\r
103 }\r
104 \r
105 static void setTxPacket(const NyLPC_TcTcpSocket_t* i_inst,void* i_tx_buf,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len)\r
106 {\r
107         struct NyLPC_TIPv4Header*       iph;\r
108         struct NyLPC_TTcpHeader*        tcph;\r
109         NyLPC_TUInt8 iph_word=0x05;\r
110         NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;\r
111         //IPヘッダの更新\r
112         iph=(struct NyLPC_TIPv4Header*)i_tx_buf;\r
113         iph->vhl=0x40|(0x0f&iph_word);\r
114         iph->destipaddr=i_inst->uip_connr.ripaddr;\r
115         iph->srcipaddr =*(i_inst->uip_connr.lipaddr);\r
116         NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);\r
117         //TCPヘッダの更新\r
118         tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));\r
119 \r
120 \r
121         //SYNが有るならMSSの書き込み\r
122         if((TCP_SYN & i_tcpf)){\r
123                 tcph_word+=((TCP_OPT_MSS_LEN) / 4);\r
124                 NyLPC_TTcpHeader_setMmsOpt(((NyLPC_TUInt8*)(tcph+1)),i_inst->uip_connr.default_mss);\r
125         }\r
126         tcph->tcpoffset=(tcph_word<<4);\r
127         setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr));\r
128 \r
129         //最終的なパケットサイズと必要ならペイロードを書き込み\r
130         if(i_buf!=NULL){\r
131                 iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4);\r
132                 memcpy(((NyLPC_TUInt8*)i_tx_buf)+((iph_word+tcph_word)*4),i_buf,i_len);\r
133         }else{\r
134                 iph->len16=NyLPC_htons((iph_word+tcph_word)*4);\r
135         }\r
136         //WND設定\r
137         tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));\r
138         //Checksumの生成\r
139         tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));\r
140         iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));\r
141         return;\r
142 }\r
143 \r
144 /**\r
145  * IP/TCPヘッダが40バイト固定として、i_tx_buf+40の位置にあるペイロードに対するIP/TCPヘッダを書き込みます。\r
146  */\r
147 static void setTxPacketHeader(const NyLPC_TcTcpSocket_t* i_inst,void* i_tx_buf,NyLPC_TUInt8 i_tcpf,NyLPC_TUInt16 i_len)\r
148 {\r
149         struct NyLPC_TIPv4Header*       iph;\r
150         struct NyLPC_TTcpHeader*        tcph;\r
151         NyLPC_TUInt8 iph_word=0x05;\r
152         NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;\r
153         //IPヘッダの更新\r
154         iph=(struct NyLPC_TIPv4Header*)i_tx_buf;\r
155         iph->vhl=0x40|(0x0f&iph_word);\r
156         iph->destipaddr=i_inst->uip_connr.ripaddr;\r
157         iph->srcipaddr =*(i_inst->uip_connr.lipaddr);\r
158         NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);\r
159 \r
160         //TCPヘッダの更新\r
161         tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));\r
162         tcph->tcpoffset=(tcph_word<<4);\r
163         setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr));\r
164 \r
165         //最終的なパケットサイズと必要ならペイロードを書き込み\r
166         iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4);\r
167         //WND設定\r
168         tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));\r
169         //Checksumの生成\r
170         tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));\r
171         iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));\r
172         return;\r
173 }\r
174 \r
175 \r
176 \r
177 \r
178 \r
179 ////////////////////////////////////////////////////////////////////////////////////////////////////\r
180 //\r
181 //      Mainclass::private\r
182 //\r
183 ////////////////////////////////////////////////////////////////////////////////////////////////////\r
184 \r
185 /**\r
186  * ACK番号を更新する。\r
187  * @param i_ackno\r
188  * ネットワークオーダーのACK番号\r
189  */\r
190 static void updateAckNo(void* i_tx_buf,NyLPC_TUInt32 i_ackno)\r
191 {\r
192         struct NyLPC_TIPv4Header*       iph=(struct NyLPC_TIPv4Header*)i_tx_buf;\r
193         struct NyLPC_TTcpHeader*        tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));\r
194 \r
195 /*      union{\r
196                 NyLPC_TUInt32 l;\r
197                 NyLPC_TUInt8 b[4];\r
198         }old_ack,new_ack;\r
199         NyLPC_TUInt16 v1;\r
200         //checksumの計算\r
201         old_ack.l=i_inst->payload.tcp->ackno32;//古いACK番号\r
202         new_ack.l=i_ackno;//新しいACK番号\r
203         v1=NyLPC_ntohs(~(i_inst->payload.tcp->tcpchksum));//1の補数を取って、ホストオーダーに戻す。\r
204         //減算\r
205         v1=sub16c(v1,(old_ack.b[0]<<8)+old_ack.b[1]);\r
206         v1=sub16c(v1,(old_ack.b[2]<<8)+old_ack.b[3]);\r
207         //加算\r
208         v1=add16c(v1,(new_ack.b[0]<<8)+new_ack.b[1]);\r
209         v1=add16c(v1,(new_ack.b[2]<<8)+new_ack.b[3]);\r
210         v1=~NyLPC_htons(v1);*/\r
211 NyLPC_Trace();\r
212         tcph->ackno32=i_ackno;\r
213 NyLPC_Trace();\r
214         tcph->tcpchksum = 0;\r
215 NyLPC_Trace();\r
216         tcph->tcpchksum = ~(NyLPC_TIPv4Header_makeTcpChecksum(iph));\r
217 NyLPC_Trace();\r
218 \r
219 /*\r
220         if((i_inst->payload.tcp->tcpchksum!=v1)){\r
221                 NyLPC_Warning();\r
222         }*/\r
223 }\r
224 \r
225 \r
226 \r
227 /**\r
228  * 指定した送信パケットがACK済であるか調べる。\r
229  */\r
230 static NyLPC_TBool isPacketAcked(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)\r
231 {\r
232         int rp;\r
233         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
234         rp=i_inst->txbuf.rp;\r
235         while(rp!=i_inst->txbuf.wp){\r
236                 if(q[rp].ackno==i_sq){\r
237                         return NyLPC_TBool_FALSE;\r
238                 }\r
239                 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;\r
240         }\r
241         return NyLPC_TBool_TRUE;\r
242 }\r
243 /**\r
244  * 送信キューからi_sq以前に送信したパケットを除外して、残り個数を返却する。\r
245  */\r
246 static int getNumOfSending(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)\r
247 {\r
248         int rp,n;\r
249         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
250         rp=i_inst->txbuf.rp;\r
251         n=0;\r
252         while(rp!=i_inst->txbuf.wp){\r
253                 if(q[rp].ackno==i_sq){\r
254                         return n;\r
255                 }\r
256                 n++;\r
257                 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;\r
258         }\r
259         return n;\r
260 }\r
261 /**\r
262  * この関数は、コネクションをリセットします。\r
263  * ロック状態でコールしてください。\r
264  * 関数は、現在バッファにある再送信待ちデータを開放します。\r
265  */\r
266 static void resetTxQWithUnlock(NyLPC_TcTcpSocket_t* i_inst)\r
267 {\r
268         int i,l;\r
269         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
270         void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];\r
271 \r
272         l=0;\r
273         while(i_inst->txbuf.rp!=i_inst->txbuf.wp){\r
274                 dlist[l]=q[i_inst->txbuf.rp].packet;\r
275                 l++;\r
276                 i_inst->txbuf.rp=(i_inst->txbuf.rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;\r
277         }\r
278         i_inst->txbuf.rp=i_inst->txbuf.wp=0;\r
279         //ロック解除\r
280         unlockResource(i_inst);\r
281         //セーブしたバッファを開放\r
282         for(i=0;i<l;i++){\r
283                 NyLPC_cUipService_releaseTxBuf(dlist[i]);\r
284         }\r
285         return;\r
286 }\r
287 /**\r
288  * TXバッファの再送パケットのACK番号を更新します。\r
289  * ロックして実行してください。\r
290  * @param i_ackno\r
291  * ネットワークオーダーのACK番号\r
292  */\r
293 static void updateTxAck(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_ackno)\r
294 {\r
295         NyLPC_TUInt8 rp;\r
296         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
297         NyLPC_ArgAssert(i_inst!=NULL);\r
298         rp=i_inst->txbuf.rp;\r
299         while(rp!=i_inst->txbuf.wp){\r
300                 updateAckNo(q[rp].packet,i_ackno);\r
301                 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;\r
302         }\r
303 }\r
304 \r
305 /**\r
306  * RTOの予測関数\r
307  */\r
308 static void estimateRTO(NyLPC_TcTcpSocket_t* i_inst,int s,int n)\r
309 {\r
310         NyLPC_TcStopwatch_t sw;\r
311         NyLPC_TUInt32 cr_rtt_min,cr_rtt_max,sk_rto,new_rto,w;\r
312         int i;\r
313         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
314         NyLPC_cStopwatch_initialize(&sw);\r
315 \r
316         sk_rto=i_inst->uip_connr.current_rto32;\r
317         //ACKされたパケットの個数は?\r
318         switch(n){\r
319         case 1:\r
320                 NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);\r
321                 cr_rtt_min=NyLPC_cStopwatch_elapseInMsec(&sw);\r
322                 if(sk_rto<cr_rtt_min){\r
323                         //現在のRTOよりも大きい→再送があった。(再送の理由が回線遅延によるものかわからないので、基本RTOを25%増やす。)\r
324                         new_rto=sk_rto*10/8;\r
325                 }else if(sk_rto/4<cr_rtt_min){\r
326                         //現在のRTOの1/4< n < 現在のRTO 想定内の変動。1/8\r
327                         new_rto=(sk_rto+(cr_rtt_min*3*7))/8;\r
328                 }else{\r
329                         //現在の1/4以下。RTOを再計算。 RTOが大きすぎるので再計算。(計測値を優先した現在値との平均値)\r
330                         new_rto=(sk_rto+(cr_rtt_min*3*3))/4;\r
331                 }\r
332                 break;\r
333         default:\r
334                 //複数のパケットなら、最大と最小の時刻を得る。\r
335                 NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);\r
336                 cr_rtt_min=cr_rtt_max=NyLPC_cStopwatch_elapseInMsec(&sw);\r
337                 for(i=1;i<n;i++){\r
338                         NyLPC_cStopwatch_set(&sw,q[(s+i)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ].tick_of_sent);\r
339                         w=NyLPC_cStopwatch_elapseInMsec(&sw);\r
340                         if(cr_rtt_min>w){\r
341                                 cr_rtt_min=w;\r
342                         }\r
343                         if(cr_rtt_max<w){\r
344                                 cr_rtt_max=w;\r
345                         }\r
346                 }\r
347                 if(sk_rto<cr_rtt_min && sk_rto<cr_rtt_max){\r
348                         //最大値,最小値とも現在のRTTより大きい→低速な回線を検出。\r
349                         new_rto=cr_rtt_max*10/8;//最大経過時間の25%増しの時間を設定。\r
350                 }else if(sk_rto/4<cr_rtt_min){\r
351                         //現在のRTOの1/4< n < 現在のRTO 想定範囲内。1/8の加重平均で速度計算。\r
352                         new_rto=(sk_rto+(cr_rtt_min*3*7))/8;\r
353                 }else{\r
354                         //現在の1/4以下。RTOが大きすぎるので再計算。(計測値を優先した加重平均)\r
355                         new_rto=(sk_rto+(cr_rtt_min*3*3))/4;\r
356                 }\r
357                 break;\r
358         }\r
359         NyLPC_cStopwatch_finalize(&sw);\r
360         if(new_rto<UIP_TCP_RTO_MINIMUM){\r
361                 new_rto=UIP_TCP_RTO_MINIMUM;\r
362         }\r
363         i_inst->uip_connr.current_rto32=new_rto;\r
364 }\r
365 \r
366 /**\r
367  * TXキューから、入力されたシーケンス番号より前のパケットを除外します。\r
368  * リングバッファのrp->wp-1までをチェックして、sqに等しいi_sq以前のパケットバッファをo_dlistへ返します。\r
369  *\r
370  */\r
371 static int updateTxQByIndex(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,void* o_dlist[])\r
372 {\r
373         int rp,n;\r
374         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
375         //ロック状態なう\r
376         rp=i_inst->txbuf.rp;\r
377         n=0;\r
378         //This is debug\r
379         DEBUG_RTO_LOG(i_inst);\r
380 \r
381         while(rp!=i_inst->txbuf.wp){\r
382                 o_dlist[n]=q[rp].packet;\r
383                 if(q[rp].ackno==i_sq){\r
384                         //i_inst->txbuf.rp->rpのパケットのRTOからbaseRTOの値を再計算。\r
385                         estimateRTO(i_inst,i_inst->txbuf.rp,n+1);\r
386                         i_inst->txbuf.rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;\r
387                         return n+1;\r
388                 }\r
389                 n++;\r
390                 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;\r
391         }\r
392         return 0;\r
393 }\r
394 \r
395 \r
396 \r
397 /**\r
398  * 空きキューを1個返します。\r
399  * 空きキューの\r
400  */\r
401 static struct NyLPC_TcTcpSocket_TxQItem* getTxQ(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TcStopwatch_t* i_timer)\r
402 {\r
403         int i;\r
404         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
405         do{\r
406                 //クローズドに遷移してしまったら、エラーである。\r
407                 if(i_inst->tcpstateflags==UIP_CLOSED){\r
408                         return NULL;\r
409                 }\r
410                 //キューの空きをチェック。wp+1==rpなら、キューがいっぱい。rp==wpなら、キューが空。\r
411                 if(((i_inst->txbuf.wp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ)==i_inst->txbuf.rp){\r
412                         //一時的なアンロック\r
413                         unlockResource(i_inst);\r
414                         //タスクスイッチ\r
415                         NyLPC_cThread_yield();\r
416                         //ロック\r
417                         lockResource(i_inst);\r
418                         continue;\r
419                 }\r
420                 i=i_inst->txbuf.wp;\r
421                 i_inst->txbuf.wp=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;\r
422                 return &(q[i]);\r
423         }while(!NyLPC_cStopwatch_isExpired(i_timer));\r
424         //失敗。タイムアウト。\r
425         return NULL;\r
426 }\r
427 \r
428 \r
429 \r
430 \r
431 \r
432 \r
433 /**********************************************************************\r
434  * public 関数
435  **********************************************************************/\r
436 \r
437 NyLPC_TBool NyLPC_cTcpSocket_initialize(NyLPC_TcTcpSocket_t* i_inst,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)\r
438 {\r
439         int i;\r
440         NyLPC_TcUipService_t* srv=_NyLPC_TcUipService_inst;\r
441         NyLPC_cBaseSocket_initialize(&(i_inst->_super),NyLPC_TcBaseSocket_TYPEID_TCP_SOCK);\r
442         //uipサービスは初期化済であること。\r
443         NyLPC_Assert(NyLPC_TcUipService_isInitService());\r
444 \r
445         NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len);\r
446         //      NyLPC_AbortIfNot(NyLPC_cMutex_initialize(&(i_inst->_smutex)));//個別Mutex\r
447 //      i_inst->_smutex=NyLPC_cIPv4_getSockMutex(&(srv->_tcpv4));//共有Mutex\r
448         i_inst->tcpstateflags=UIP_CLOSED;\r
449         i_inst->txbuf.rp=i_inst->txbuf.wp=0;\r
450         for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){\r
451                 i_inst->txbuf.txq[i].packet=NULL;\r
452         }\r
453         //管理リストへ登録。\r
454         return NyLPC_cIPv4_addSocket(&(srv->_tcpv4),&(i_inst->_super));\r
455 }\r
456 void NyLPC_cTcpSocket_finalize(NyLPC_TcTcpSocket_t* i_inst)\r
457 {\r
458         int i;\r
459         NyLPC_TcUipService_t* srv=_NyLPC_TcUipService_inst;\r
460         NyLPC_Assert(NyLPC_TcUipService_isInitService());\r
461         //uipサービスは初期化済であること。\r
462         if(!NyLPC_cIPv4_removeSocket(&(srv->_tcpv4),&(i_inst->_super))){\r
463                 //削除失敗、それは死を意味する。\r
464                 NyLPC_Abort();\r
465         }\r
466         //開放漏れの保険\r
467         if(i_inst->txbuf.rp!=i_inst->txbuf.wp){\r
468                 lockResource(i_inst);\r
469                 resetTxQWithUnlock(i_inst);\r
470         }\r
471         for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){\r
472                 i_inst->txbuf.txq[i].packet=NULL;\r
473         }\r
474         NyLPC_cFifoBuffer_finalize(&(i_inst->rxbuf));\r
475 //      NyLPC_cMutex_finalize(&(i_inst->_smutex));\r
476         NyLPC_cBaseSocket_finalize(&(i_inst->_super));\r
477         return;\r
478 }\r
479 \r
480 \r
481 \r
482 NyLPC_TBool NyLPC_cTcpSocket_listenSyn(NyLPC_TcTcpSocket_t* i_inst,const struct NyLPC_TTcpSocketSynParam* i_lq,NyLPC_TUInt16 i_lport)\r
483 {\r
484 //      NyLPC_Assert(NyLPC_cMutex_isLocked(i_inst->_smutex));\r
485         lockResource(i_inst);\r
486         //ソケットが無効であること。\r
487         if(i_inst->tcpstateflags==UIP_CLOSED)\r
488         {\r
489                 //localipとdefault_mmsは別枠で設定\r
490                 /* Fill in the necessary fields for the new connection. */\r
491                 i_inst->uip_connr.current_rto32 = UIP_TCP_RTO_INITIAL;\r
492                 i_inst->uip_connr.lport = i_lport;\r
493                 i_inst->uip_connr.rport = i_lq->rport;\r
494                 i_inst->uip_connr.ripaddr=i_lq->srcaddr;\r
495                 i_inst->uip_connr.snd_nxt32=iss32;\r
496                 /* rcv_nxt should be the seqno from the incoming packet + 1. */\r
497                 i_inst->uip_connr.rcv_nxt32= i_lq->rcv_nxt32;\r
498                 //MSSの設定\r
499                 i_inst->uip_connr.peer_mss=(i_lq->mss!=0)?i_lq->mss:i_inst->uip_connr.default_mss;\r
500                 i_inst->uip_connr.peer_win=0;\r
501                 NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));\r
502                 //ここでステータスがかわる。\r
503                 i_inst->tcpstateflags = UIP_SYN_RCVD;\r
504                 //前回のデータが残っていた場合の保険\r
505                 if(i_inst->txbuf.rp!=i_inst->txbuf.wp){\r
506                         resetTxQWithUnlock(i_inst);\r
507                 }else{\r
508                         unlockResource(i_inst);\r
509                 }\r
510                 return NyLPC_TBool_TRUE;\r
511         }\r
512         unlockResource(i_inst);\r
513         return NyLPC_TBool_FALSE;\r
514 }\r
515 \r
516 \r
517 /**\r
518  * sq番のTxがキューから消え去るのを待ちます。\r
519  * この関数は、アンロック状態でコールしてください。\r
520  * <div>\r
521  * パケットがキューからなくなる条件は、以下の2つです。\r
522  * <ul>\r
523  * <li>ACKを受信してパケットキューが更新された。</li>\r
524  * <li>RSTを受信して(CLOSEDに遷移して)、キューがクリアされた。</li>\r
525  * <li>送信タイムアウトで関数が(CLOSEDに遷移させて)キューをクリアした。</li>\r
526  * </ul>\r
527  * </div>\r
528  * @param i_wait_msec\r
529  * @return\r
530  * 1番目の条件でパケットが消失したときのみ、TRUEを返します。\r
531  * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。\r
532  */\r
533 static NyLPC_TBool waitForTxRemove(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,NyLPC_TcStopwatch_t* i_timer)\r
534 {\r
535         NyLPC_TUInt8 f;\r
536         lockResource(i_inst);\r
537         do{\r
538                 //パケットが送信中か調べる。\r
539                 if(!isPacketAcked(i_inst,i_sq)){\r
540                         //まだある場合は、タスクスイッチを繰り返して消失を待つ。\r
541                         unlockResource(i_inst);\r
542                         NyLPC_cThread_yield();\r
543                         lockResource(i_inst);\r
544                         continue;\r
545                 }\r
546                 //なくなった場合は、原因を調べる。\r
547                 f=i_inst->tcpstateflags;\r
548                 unlockResource(i_inst);\r
549                 return (f==UIP_CLOSED)?NyLPC_TBool_FALSE:NyLPC_TBool_TRUE;\r
550         }while(!NyLPC_cStopwatch_isExpired(i_timer));\r
551         unlockResource(i_inst);\r
552         return NyLPC_TBool_FALSE;\r
553 }\r
554 \r
555 \r
556 /**\r
557  * 再送信処理をセットして、パケットを送信します。\r
558  * この関数は「アンロック状態で」実行してください。\r
559  * @param i_len\r
560  * 送信データサイズを指定します。\r
561  * この番号は、シーケンス番号の加算値ではありませんので、注意をしてください。\r
562  * @return\r
563  * <ul>\r
564  * <li>n=-1:送信キューへの投入に失敗した。</li>\r
565  * <li>n>=0:nバイトのデータを送信キューへの投入することに成功した。</li>\r
566  * </ul>\r
567  * 送信キューに失敗する理由は2つあります。1つは、TXバッファがフルでタイムアウト。もうひとつは、非同期なコネクリョンのリセットです。\r
568  * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。\r
569  */\r
570 static NyLPC_TInt32 sendWithRetransmit(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len,NyLPC_TcStopwatch_t* i_timer,NyLPC_TUInt32* o_ack)\r
571 {\r
572         struct NyLPC_TcTcpSocket_TxQItem* txq;\r
573         NyLPC_TUInt16 s;\r
574         void* buf;\r
575         NyLPC_TUInt32 next_ack;\r
576         //送信バッファを取得\r
577         //@bug オブションパケット送信時に4バイト足りないメモリ要求しない?問題になってないけど。\r
578         for(;;){\r
579                 buf=NyLPC_cUipService_allocTxBuf(i_len+(SIZE_OF_IPv4_TCPIP_HEADER),&s);\r
580                 if(buf!=NULL){\r
581                         break;\r
582                 }\r
583                 //タイムアウト確認\r
584                 if(NyLPC_cStopwatch_isExpired(i_timer)){\r
585                         return -1;\r
586                 }\r
587         };\r
588         lockResource(i_inst);\r
589         //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。\r
590         if(i_len>0){\r
591                 while(i_inst->uip_connr.peer_win==0){\r
592                         unlockResource(i_inst);\r
593                         //時間切れならエラー。\r
594                         if(NyLPC_cStopwatch_isExpired(i_timer)){\r
595                                 return -1;\r
596                         }\r
597                         NyLPC_cThread_yield();\r
598                         lockResource(i_inst);\r
599                 }\r
600         }\r
601         //送信キューの取得\r
602         txq=getTxQ(i_inst,i_timer);\r
603         //送信キューが取れなかった。\r
604         if(txq==NULL){\r
605                 //シーケンス番号をロールバックできないので、エラーとする。\r
606                 unlockResource(i_inst);\r
607                 NyLPC_cUipService_releaseTxBuf(buf);\r
608                 return -1;\r
609         }\r
610 \r
611         //送信バッファを基準とした送信サイズを計算\r
612         s-=SIZE_OF_IPv4_TCPIP_HEADER;\r
613         //送信サイズよりMMSが小さければ、送信サイズを修正\r
614         if(i_inst->uip_connr.peer_mss<s){\r
615                 s=i_inst->uip_connr.peer_mss;\r
616         }\r
617         //送信サイズよりpeerのウインドウサイズが小さければ修正\r
618         if(i_inst->uip_connr.peer_win<s){\r
619                 s=i_inst->uip_connr.peer_win;\r
620         }\r
621         //送信サイズより、データサイズが小さければ、送信サイズを修正\r
622         if(i_len<s){\r
623                 s=i_len;\r
624         }\r
625         //ACK番号の計算\r
626         next_ack=i_inst->uip_connr.snd_nxt32+s+(((i_tcpf&(TCP_FIN|TCP_SYN))!=0x00)?1:0);\r
627         txq->rto32=i_inst->uip_connr.current_rto32;\r
628         txq->tick_of_sent=NyLPC_cStopwatch_now();\r
629 \r
630         //パケットの書き込み\r
631         setTxPacket(i_inst,buf,i_tcpf,i_buf,s);\r
632         txq->packet=buf;\r
633 \r
634         //シーケンス番号の更新\r
635         i_inst->uip_connr.snd_nxt32=next_ack;\r
636         //Peerのウインドウサイズを更新\r
637         i_inst->uip_connr.peer_win-=s;\r
638         //ACK番号の返却\r
639         *o_ack=txq->ackno=NyLPC_HTONL(next_ack);\r
640         unlockResource(i_inst);\r
641         NyLPC_cUipService_sendIPv4Tx(buf);\r
642         return s;\r
643 }\r
644 /**\r
645  * RSTを1フレームだけ送信します。\r
646  * この関数は、クローズドステータスのソケットにしてからコールします。\r
647  * この関数は、アンロック状態でコールしてね。
648  */\r
649 static void sendRst(NyLPC_TcTcpSocket_t* i_inst)\r
650 {\r
651         void* buf;\r
652 \r
653         NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);\r
654         //ペイロードライタの初期化\r
655 \r
656         //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。\r
657         buf=NyLPC_cUipService_allocSysTxBuf();\r
658         lockResource(i_inst);\r
659         i_inst->uip_connr.snd_nxt32++;\r
660         unlockResource(i_inst);\r
661         setTxPacket(i_inst,buf,TCP_RST|TCP_ACK,NULL,0);\r
662         NyLPC_cUipService_sendIPv4Tx(buf);\r
663         NyLPC_cUipService_releaseTxBuf(buf);\r
664         NyLPC_cIPv4Payload_finalize(&ipv4);\r
665         return;\r
666 }\r
667 \r
668 \r
669 \r
670 /**\r
671  * 受信データをバッファに書き込む。\r
672  * 十分な空き領域がない場合、失敗する。\r
673  * この関数は、ロックして実行してください。\r
674  */\r
675 static NyLPC_TBool addRecvData(NyLPC_TcTcpSocket_t* i_inst,const void* i_data,NyLPC_TUInt16 i_data_size)\r
676 {\r
677         //受信データサイズを確認\r
678         if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))>=i_data_size){\r
679                 //バッファに格納可能なら、格納。\r
680                 NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),i_data,i_data_size);\r
681         }else{\r
682                 //エラー:ドロップする。\r
683                 return NyLPC_TBool_FALSE;\r
684         }\r
685 \r
686         return NyLPC_TBool_TRUE;\r
687 }\r
688 \r
689 \r
690 \r
691 \r
692 /**\r
693  * Public function\r
694  */\r
695 \r
696 NyLPC_TBool NyLPC_cTcpSocket_connect(NyLPC_TcTcpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_peer_port,NyLPC_TUInt32 i_wait_in_msec)\r
697 {\r
698         volatile NyLPC_TUInt8 f;\r
699         NyLPC_TUInt32 sq;\r
700         NyLPC_TcStopwatch_t sw;\r
701         NyLPC_TUInt16 lport;\r
702         lockResource(i_inst);\r
703         //ソケットが無効であること。\r
704         if(i_inst->tcpstateflags!=UIP_CLOSED)\r
705         {\r
706                 NyLPC_OnErrorGoto(Error);\r
707         }\r
708         //ポート番号の取得(lockResourceが他のソケットと共有なので、重複ポートの割当は起こりえない。でもちょっと注意して)\r
709         lport=NyLPC_htons(NyLPC_cIPv4_getNewPortNumber(i_inst->_super._parent_ipv4));\r
710         if(lport==0){\r
711                 NyLPC_OnErrorGoto(Error);\r
712         }\r
713         //connectの為の準備\r
714 \r
715         //localipとdefault_mmsは別枠で設定\r
716         /* Fill in the necessary fields for the new connection. */\r
717         i_inst->uip_connr.current_rto32 = UIP_TCP_RTO_CONNECTION_INITIAL;//RTOを短くしてARP発行時の再接続短縮を期待する。\r
718         i_inst->uip_connr.lport = lport;\r
719         i_inst->uip_connr.rport = NyLPC_htons(i_peer_port);\r
720         i_inst->uip_connr.ripaddr=*i_addr;\r
721         i_inst->uip_connr.snd_nxt32=iss32;//should be random\r
722         /* rcv_nxt should be the seqno from the incoming packet + 1. */\r
723         i_inst->uip_connr.rcv_nxt32=0;\r
724         //MSSの設定\r
725         i_inst->uip_connr.peer_mss=i_inst->uip_connr.default_mss;\r
726         i_inst->uip_connr.peer_win=1;//periodicの再送信を期待するために相手のWindowサイズは1と仮定する。\r
727         NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));\r
728         //ここでステータスがかわる。\r
729         i_inst->tcpstateflags = UIP_SYN_SENT;\r
730         //前回のデータが残っていた場合の保険\r
731         if(i_inst->txbuf.rp!=i_inst->txbuf.wp){\r
732                 resetTxQWithUnlock(i_inst);\r
733         }else{\r
734                 unlockResource(i_inst);\r
735         }\r
736 \r
737         NyLPC_cStopwatch_initialize(&sw);\r
738 \r
739         NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);\r
740         if(sendWithRetransmit(i_inst,TCP_SYN,NULL,0,&sw,&sq)==0){\r
741                 //ちょっと待つ。\r
742                 NyLPC_cThread_yield();\r
743                 //キューにあるTXが消えるのを待つ。\r
744                 if(waitForTxRemove(i_inst,sq,&sw)){\r
745                         //ACK受信に成功して、TXが消失\r
746                         NyLPC_cStopwatch_finalize(&sw);\r
747                         return NyLPC_TBool_TRUE;\r
748                 }\r
749         }\r
750         //ロックして、強制的なステータス遷移\r
751         lockResource(i_inst);\r
752         f=i_inst->tcpstateflags;\r
753         if(f!=UIP_CLOSED){\r
754                 //もし、強制CLOSE遷移であれば、RSTも送信。\r
755                 i_inst->tcpstateflags=UIP_CLOSED;\r
756                 unlockResource(i_inst);\r
757                 sendRst(i_inst);\r
758         }else{\r
759                 unlockResource(i_inst);\r
760         }\r
761         return NyLPC_TBool_FALSE;\r
762 Error:\r
763         unlockResource(i_inst);\r
764         return NyLPC_TBool_FALSE;\r
765 }\r
766 \r
767 /**\r
768  * この関数は、UIP_SYN_RCVDステータスのソケットを、ESTABLISHEDへ遷移させます。\r
769  * cTcpListener_listen関数を通過したインスタンスに実行してください。\r
770  * この関数は、アプリケーションが呼び出します。\r
771  * @return\r
772  *\r
773  */\r
774 NyLPC_TBool NyLPC_cTcpSocket_accept(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)\r
775 {\r
776         volatile NyLPC_TUInt8 f;\r
777         NyLPC_TUInt32 sq;\r
778         NyLPC_TcStopwatch_t sw;\r
779 \r
780         NyLPC_cStopwatch_initialize(&sw);\r
781         //ステータスチェック\r
782         f=i_inst->tcpstateflags;\r
783         switch(f)\r
784         {\r
785         case UIP_ESTABLISHED:\r
786                 return NyLPC_TBool_TRUE;\r
787         case UIP_SYN_RCVD:\r
788                 //処理対象\r
789                 break;\r
790         default:\r
791                 return NyLPC_TBool_FALSE;\r
792         }\r
793         NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);\r
794         if(sendWithRetransmit(i_inst,TCP_SYN|TCP_ACK,NULL,0,&sw,&sq)==0){\r
795                 //ちょっと待つ。\r
796                 NyLPC_cThread_yield();\r
797                 //キューにあるTXが消えるのを待つ。\r
798                 if(waitForTxRemove(i_inst,sq,&sw)){\r
799                         //ACK受信に成功して、TXが消失\r
800                         NyLPC_cStopwatch_finalize(&sw);\r
801                         return NyLPC_TBool_TRUE;\r
802                 }\r
803         }\r
804         //ロックして、強制的なステータス遷移\r
805         lockResource(i_inst);\r
806         f=i_inst->tcpstateflags;\r
807         if(f!=UIP_CLOSED){\r
808                 //もし、強制CLOSE遷移であれば、RSTも送信。\r
809                 i_inst->tcpstateflags=UIP_CLOSED;\r
810                 unlockResource(i_inst);\r
811                 sendRst(i_inst);\r
812         }else{\r
813                 unlockResource(i_inst);\r
814         }\r
815         return NyLPC_TBool_FALSE;\r
816 }\r
817 \r
818 \r
819 /**\r
820  * この関数は、ソケットの受信バッファの読み取り位置と、読み出せるデータサイズを返却します。\r
821  * 関数はポインターを返却するだけで、バッファの読み取り位置をシークしません。\r
822  * シークするにはNyLPC_cTcpSocket_pseekを使います。\r
823  */\r
824 NyLPC_TInt32 NyLPC_cTcpSocket_precv(NyLPC_TcTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec)\r
825 {\r
826         volatile NyLPC_TUInt8 st;\r
827         NyLPC_TUInt16 rlen;\r
828         //タイマを生成\r
829         NyLPC_TcStopwatch_t sw;\r
830         NyLPC_cStopwatch_initialize(&sw);\r
831 \r
832         //ESTABLISHED以外の場合は、エラー。\r
833         NyLPC_cStopwatch_setNow(&sw);\r
834         do{\r
835                 //読み出しバッファ情報のコピー\r
836                 //MUTEX LOCK\r
837                 lockResource(i_inst);\r
838                 st=i_inst->tcpstateflags;\r
839                 rlen=NyLPC_cFifoBuffer_getLength(&(i_inst->rxbuf));\r
840                 *o_buf_ptr=NyLPC_cFifoBuffer_getPtr(&(i_inst->rxbuf));\r
841                 //MUTEX UNLOCK\r
842                 unlockResource(i_inst);\r
843 \r
844                 //バッファが空の場合は、ステータスチェック。ESTABLISHEDでなければ、エラー(PASVCLOSE等の場合)\r
845                 switch(st){\r
846                 case UIP_ESTABLISHED:\r
847                         if(rlen>0){\r
848                                 //バッファにパケットがあれば返却\r
849                                 NyLPC_cStopwatch_finalize(&sw);\r
850                                 return rlen;\r
851                         }\r
852                         break;\r
853                 case UIP_CLOSE_WAIT:\r
854                         if(rlen>0){\r
855                                 //バッファにパケットがあれば返却\r
856                                 NyLPC_cStopwatch_finalize(&sw);\r
857                                 return rlen;\r
858                         }\r
859                         //引き続きエラー処理\r
860                 default:\r
861                         //他の場合はエラー\r
862                         NyLPC_cStopwatch_finalize(&sw);\r
863                         return -1;\r
864                 }\r
865                 //タスクスイッチ\r
866                 NyLPC_cThread_yield();\r
867         }while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec);\r
868         //規定時間内に受信が成功しなかった。\r
869         NyLPC_cStopwatch_finalize(&sw);\r
870         return 0;\r
871 }\r
872 /**\r
873  * 受信バッファをシークします。\r
874  * シーク後に、遅延ACKを送出します。
875  */\r
876 void NyLPC_cTcpSocket_pseek(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek)\r
877 {\r
878         void* buf;\r
879         NyLPC_ArgAssert(i_seek<=NyLPC_cFifoBuffer_getLength(&(i_inst->rxbuf)));\r
880         if(i_seek==0){\r
881                 return;\r
882         }\r
883 \r
884         //ACK送信バッファの取得\r
885         buf=NyLPC_cUipService_allocSysTxBuf();\r
886 \r
887         //MUTEX LOCK\r
888         lockResource(i_inst);\r
889 \r
890         //受信バッファを読み出しシーク\r
891         NyLPC_cFifoBuffer_pop(&(i_inst->rxbuf),i_seek);\r
892         //ACKパケットの生成\r
893         setTxPacket(i_inst,buf,TCP_ACK,NULL,0);\r
894         unlockResource(i_inst);\r
895         //ACK送信\r
896         NyLPC_cUipService_sendIPv4Tx(buf);\r
897         NyLPC_cUipService_releaseTxBuf(buf);\r
898 \r
899 }\r
900 \r
901 /**\r
902  * See header file.\r
903  */\r
904 void* NyLPC_cTcpSocket_allocSendBuf(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec)\r
905 {\r
906         NyLPC_TUInt16 s;\r
907         void* buf;\r
908         NyLPC_TcStopwatch_t sw;\r
909 \r
910         NyLPC_cStopwatch_initialize(&sw);\r
911         NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);\r
912 \r
913         //送信バッファを取得\r
914         //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。\r
915         for(;;){\r
916                 //ESTABLISHED以外に非同期遷移\r
917                 if(i_inst->tcpstateflags!=UIP_ESTABLISHED){\r
918                         NyLPC_cStopwatch_finalize(&sw);\r
919                         return NULL;\r
920                 }\r
921                 buf=NyLPC_cUipService_allocTxBuf(i_hint+(SIZE_OF_IPv4_TCPIP_HEADER),&s);\r
922                 if(buf!=NULL){\r
923                         break;\r
924                 }\r
925                 //タイムアウト時もエラー\r
926                 if(NyLPC_cStopwatch_isExpired(&sw)){\r
927                         NyLPC_cStopwatch_finalize(&sw);\r
928                         return NULL;\r
929                 }\r
930         }\r
931 \r
932 //@todo 前段処理と順番を入れ替えて、要求サイズとpeerのwinのうち、小さいほうを割り当てたほうが良くない?\r
933 //ここで相手のwin待ちをする理由は、相手に確実に受け取れるサイズを決定する為。\r
934         lockResource(i_inst);\r
935         //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。\r
936         while(i_inst->uip_connr.peer_win==0){\r
937                 unlockResource(i_inst);\r
938                 //ESTABLISHED以外に非同期遷移 orタイムアウト確認\r
939                 if(NyLPC_cStopwatch_isExpired(&sw)||(i_inst->tcpstateflags!=UIP_ESTABLISHED)){\r
940                         NyLPC_cUipService_releaseTxBuf(buf);\r
941                         NyLPC_cStopwatch_finalize(&sw);\r
942                         return NULL;\r
943                 }\r
944                 NyLPC_cThread_yield();\r
945                 lockResource(i_inst);\r
946         }\r
947         //送信バッファを基準とした送信サイズを計算\r
948         s-=SIZE_OF_IPv4_TCPIP_HEADER;\r
949         //送信サイズよりMMSが小さければ、送信サイズを修正\r
950         if(i_inst->uip_connr.peer_mss<s){\r
951                 s=i_inst->uip_connr.peer_mss;\r
952         }\r
953         //送信サイズよりpeerのウインドウサイズが小さければ修正\r
954         if(i_inst->uip_connr.peer_win<s){\r
955                 s=i_inst->uip_connr.peer_win;\r
956         }\r
957         unlockResource(i_inst);\r
958         //バッファサイズ確定。\r
959         *o_buf_size=s;\r
960         NyLPC_cStopwatch_finalize(&sw);\r
961         return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_TCPIP_HEADER;\r
962 }\r
963 /**\r
964  * See Header file.\r
965  */\r
966 void NyLPC_cTcpSocket_releaseSendBuf(NyLPC_TcTcpSocket_t* i_inst,void* i_buf_ptr)\r
967 {\r
968         NyLPC_cUipService_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER);\r
969 }\r
970 \r
971 \r
972 /**\r
973  * 事前にAllocしたTxパケットを送信します。\r
974  * このAPIはゼロコピー送信をサポートするためのものです。\r
975  * @param i_buf_ptr\r
976  * allocSendBufで取得したメモリを指定します。\r
977  * @return\r
978  * 関数が失敗した場合、i_buf_ptrは「開放されません。」\r
979  */\r
980 NyLPC_TBool NyLPC_cTcpSocket_psend(NyLPC_TcTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec)\r
981 {\r
982         struct NyLPC_TcTcpSocket_TxQItem* txq;\r
983         void* buf;\r
984         NyLPC_TcStopwatch_t sw;\r
985         //ESTABLISHEDでなければエラー\r
986         if(i_inst->tcpstateflags!=UIP_ESTABLISHED){\r
987                 //ESTABLISHEDでなければエラー\r
988                 return NyLPC_TBool_FALSE;\r
989         }\r
990         //送信データ0なら何もしない。\r
991         if(i_len<1){\r
992                 NyLPC_cTcpSocket_releaseSendBuf(i_inst,i_buf_ptr);\r
993                 return NyLPC_TBool_TRUE;\r
994         }\r
995         NyLPC_cStopwatch_initialize(&sw);\r
996         NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);\r
997 \r
998         //先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定\r
999         buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER;\r
1000         lockResource(i_inst);\r
1001         //送信キューの取得\r
1002         txq=getTxQ(i_inst,&sw);\r
1003         //送信キューが取れなかった。\r
1004         if(txq==NULL){\r
1005                 //シーケンス番号をロールバックできないので、エラーとする。\r
1006                 unlockResource(i_inst);\r
1007                 NyLPC_cStopwatch_finalize(&sw);\r
1008                 return NyLPC_TBool_FALSE;\r
1009         }\r
1010         //ここから先はi_bufの所有権はインスタンスになってる。\r
1011 \r
1012         //IPv4ペイロードの書き込み\r
1013 \r
1014         //allocをした時点でwin,mssは考慮されているので、そのままそうしんしる。\r
1015 \r
1016         //ACK番号の計算\r
1017         txq->rto32=i_inst->uip_connr.current_rto32;\r
1018         txq->tick_of_sent=NyLPC_cStopwatch_now();\r
1019         //パケットヘッダの生成(ヘッダ長はpreadで定義した値(4+6)*4=40です。)\r
1020         setTxPacketHeader(i_inst,buf,TCP_ACK|TCP_PSH,i_len);\r
1021         txq->packet=buf;\r
1022 \r
1023         //シーケンス番号の更新\r
1024         i_inst->uip_connr.snd_nxt32=i_inst->uip_connr.snd_nxt32+i_len;\r
1025         //Peerのウインドウサイズを更新\r
1026         i_inst->uip_connr.peer_win-=i_len;\r
1027         //ACK番号の返却\r
1028         txq->ackno=NyLPC_HTONL(i_inst->uip_connr.snd_nxt32);\r
1029         unlockResource(i_inst);\r
1030         NyLPC_cUipService_sendIPv4Tx(buf);\r
1031         NyLPC_cStopwatch_finalize(&sw);\r
1032         return NyLPC_TBool_TRUE;\r
1033 }\r
1034 \r
1035 /**\r
1036  * See header file.\r
1037  */\r
1038 NyLPC_TInt32 NyLPC_cTcpSocket_send(NyLPC_TcTcpSocket_t* i_inst,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec)\r
1039 {\r
1040         NyLPC_TInt16 hint;\r
1041         NyLPC_TUInt16 s;\r
1042         void* buf;\r
1043         if(i_len<1){\r
1044                 return 0;\r
1045         }\r
1046         hint=(i_len>32767)?32767:i_len;\r
1047         buf=NyLPC_cTcpSocket_allocSendBuf(i_inst,hint,&s,i_wait_in_msec);\r
1048         if(buf==NULL){\r
1049                 return -1;\r
1050         }\r
1051         //送信サイズの計算\r
1052         s=((NyLPC_TInt32)s<i_len)?s:(NyLPC_TUInt16)i_len;\r
1053         memcpy(buf,i_buf_ptr,s);\r
1054         if(!NyLPC_cTcpSocket_psend(i_inst,buf,s,i_wait_in_msec)){\r
1055                 NyLPC_cTcpSocket_releaseSendBuf(i_inst,buf);\r
1056                 return -1;//error\r
1057         }\r
1058         return s;\r
1059 }\r
1060 \r
1061 \r
1062 void NyLPC_cTcpSocket_close(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)\r
1063 {\r
1064         NyLPC_TcStopwatch_t sw;\r
1065         volatile NyLPC_TUInt8 f;\r
1066         NyLPC_TUInt32 sq;\r
1067         NyLPC_cStopwatch_initialize(&sw);\r
1068         NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);\r
1069         lockResource(i_inst);\r
1070 \r
1071         f=i_inst->tcpstateflags;\r
1072         //ステータスチェック\r
1073         switch(f)\r
1074         {\r
1075         case UIP_CLOSED:\r
1076                 //閉じている。\r
1077                 goto ReturnWithUnlock;\r
1078         case UIP_ESTABLISHED:\r
1079                 //アクティブクローズ。\r
1080                 i_inst->tcpstateflags=UIP_FIN_WAIT_1;\r
1081                 //送信のために一旦解除\r
1082                 unlockResource(i_inst);\r
1083                 //FINの送信\r
1084                 if(sendWithRetransmit(i_inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){\r
1085                         //ちょっと待つ。\r
1086                         NyLPC_cThread_yield();\r
1087                         //TXの消去待ち\r
1088                         if(waitForTxRemove(i_inst,sq,&sw)){\r
1089                                 //再ロック\r
1090                                 lockResource(i_inst);\r
1091                                 //タイムアウトするか、UIP_CLOSED、もしくはTIME_WAITに遷移するのを待つ。(遷移はRxprocで自動的に実行。)\r
1092                                 do{\r
1093                                         switch(i_inst->tcpstateflags)\r
1094                                         {\r
1095                                         case UIP_TIME_WAIT:\r
1096                                                 i_inst->tcpstateflags=UIP_CLOSED;\r
1097                                         case UIP_CLOSED:\r
1098                                                 NyLPC_Assert(i_inst->txbuf.rp==i_inst->txbuf.wp);\r
1099                                                 //成功。\r
1100                                                 goto ReturnWithUnlock;\r
1101                                         case UIP_FIN_WAIT_1:\r
1102                                         case UIP_FIN_WAIT_2:\r
1103                                         case UIP_CLOSING:\r
1104                                                 //一時的なアンロック\r
1105                                                 unlockResource(i_inst);\r
1106                                                 NyLPC_cThread_yield();\r
1107                                                 lockResource(i_inst);\r
1108                                         default:\r
1109                                                 break;\r
1110                                         }\r
1111                                 }while(!NyLPC_cStopwatch_isExpired(&sw));\r
1112                                 unlockResource(i_inst);\r
1113                         }\r
1114                 }\r
1115                 break;\r
1116         case UIP_CLOSE_WAIT:\r
1117                 //LAST_ACKへ遷移\r
1118                 i_inst->tcpstateflags=UIP_LAST_ACK;\r
1119                 //送信のために一旦解除\r
1120                 unlockResource(i_inst);\r
1121                 if(sendWithRetransmit(i_inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){\r
1122                         //ちょっと待つ。\r
1123                         NyLPC_cThread_yield();\r
1124                         //TXの消去待ち\r
1125                         if(waitForTxRemove(i_inst,sq,&sw)){\r
1126                                 //再ロック\r
1127                                 lockResource(i_inst);\r
1128                                 //TX消去後にCLOSEDに遷移していればOK\r
1129                                 if(i_inst->tcpstateflags==UIP_CLOSED)\r
1130                                 {\r
1131                                         NyLPC_Assert(i_inst->txbuf.rp==i_inst->txbuf.wp);\r
1132                                         goto ReturnWithUnlock;\r
1133                                 }\r
1134                                 unlockResource(i_inst);\r
1135                         }\r
1136                 }\r
1137                 //エラー。RSTで切断。\r
1138                 break;\r
1139         default:\r
1140                 unlockResource(i_inst);\r
1141                 NyLPC_Warning();\r
1142                 break;\r
1143         }\r
1144 //      if(i_inst->_smutex._lock_count>0){\r
1145 //              NyLPC_Warning();\r
1146 //      }\r
1147         //このパスに到達するのは、FIN送信/ACKに成功したにも拘らず、規定時間内にCLOSEDに遷移しなかった場合。\r
1148         //コネクションを強制遷移して、RST\r
1149         lockResource(i_inst);\r
1150         f=i_inst->tcpstateflags;\r
1151         if(f!=UIP_CLOSED){\r
1152                 //もし、強制CLOSE遷移であれば、RSTも送信。\r
1153                 i_inst->tcpstateflags=UIP_CLOSED;\r
1154                 unlockResource(i_inst);\r
1155                 sendRst(i_inst);\r
1156         }else{\r
1157                 unlockResource(i_inst);\r
1158         }\r
1159         NyLPC_cStopwatch_finalize(&sw);\r
1160         return;\r
1161 ReturnWithUnlock:\r
1162         unlockResource(i_inst);\r
1163         NyLPC_cStopwatch_finalize(&sw);\r
1164         return;\r
1165 }\r
1166 \r
1167 /**\r
1168  * uipサービスタスクが実行する関数です。\r
1169  * 定期的に実行する関数。最低でも1s単位で実行してください。\r
1170  */\r
1171 void NyLPC_cTcpSocket_periodic(\r
1172         NyLPC_TcTcpSocket_t* i_inst)\r
1173 {\r
1174         int i;\r
1175         struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;\r
1176         NyLPC_TcStopwatch_t sw;\r
1177         NyLPC_TUInt32 now;\r
1178         int rp;\r
1179         NyLPC_cStopwatch_initialize(&sw);\r
1180         now=NyLPC_cStopwatch_now();\r
1181         //MUTEX LOCK\r
1182         lockResource(i_inst);\r
1183         if(i_inst->tcpstateflags==UIP_CLOSED)\r
1184         {\r
1185                 //CLOSEDなら、バッファ開放。\r
1186                 resetTxQWithUnlock(i_inst);\r
1187         }else if(i_inst->txbuf.rp==i_inst->txbuf.wp){\r
1188                 //再送信パケットがなければ何もしないよ。\r
1189                 unlockResource(i_inst);\r
1190         }else if(i_inst->uip_connr.peer_win==0){\r
1191                 //peer_winが0の場合は何もしない。\r
1192                 unlockResource(i_inst);\r
1193         }else{\r
1194                 //再送信処理\r
1195                 rp=i_inst->txbuf.rp;\r
1196                 NyLPC_cStopwatch_set(&sw,q[rp].tick_of_sent);\r
1197                 if(NyLPC_cStopwatch_elapseInMsec(&sw)>q[rp].rto32){\r
1198                         //最古のパケットの送信時間をチェックして、タイムアウトが発生したら、再送時間と送信時刻をセット\r
1199                         //最古パケットRTOを2倍。\r
1200                         q[rp].rto32*=2;\r
1201                         for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){\r
1202                                 q[i].tick_of_sent=now;\r
1203                         }\r
1204                         if(q[rp].rto32>UIP_IP_RTO_MAX_RTO){\r
1205                                 //最古のRTOが64秒を超えたら、CLOSED\r
1206                                 i_inst->tcpstateflags =UIP_CLOSED;\r
1207                                 resetTxQWithUnlock(i_inst);\r
1208                                 sendRst(i_inst);\r
1209                         }else{\r
1210                                 //規定時間内なら、再送処理\r
1211                                 for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){\r
1212 //                                      NyLPC_cUipService_sendIPv4Tx(NyLPC_cIPv4Payload_getBuf(&(q[i].data)));\r
1213                                         NyLPC_cUipService_sendIPv4Tx(q[i].packet);\r
1214                                 }\r
1215                                 unlockResource(i_inst);\r
1216                         }\r
1217                 }else{\r
1218                         unlockResource(i_inst);\r
1219                 }\r
1220         }\r
1221         NyLPC_cStopwatch_finalize(&sw);\r
1222         return;\r
1223 }\r
1224 /**\r
1225  * uipサービスタスクが実行する関数です。\r
1226  * サービスの開始を通知します。\r
1227  */\r
1228 void NyLPC_cTcpSocket_startService(NyLPC_TcTcpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config)\r
1229 {\r
1230         NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);//閉じてなければおかしい。\r
1231         i_inst->uip_connr.lipaddr=&(i_config->ip_addr);\r
1232         i_inst->uip_connr.default_mss=i_config->default_mss;\r
1233         //NyLPC_cTcpSocket_setSynPayload関数でも実行するけど、IFのリセット時なのでここでもやる。\r
1234         NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));\r
1235         return;\r
1236 }\r
1237 /**\r
1238  * uipサービスタスクが実行する関数です。\r
1239  * サービスの停止を通知します。\r
1240  */\r
1241 void NyLPC_cTcpSocket_stopService(NyLPC_TcTcpSocket_t* i_inst)\r
1242 {\r
1243         lockResource(i_inst);\r
1244         if(i_inst->tcpstateflags==UIP_CLOSED)\r
1245         {\r
1246                 unlockResource(i_inst);\r
1247         }else{\r
1248                 i_inst->tcpstateflags=UIP_CLOSED;\r
1249                 resetTxQWithUnlock(i_inst);\r
1250                 sendRst(i_inst);\r
1251         }\r
1252         return;\r
1253 }\r
1254 \r
1255 \r
1256 void* NyLPC_cTcpSocket_parseRx(\r
1257         NyLPC_TcTcpSocket_t* i_inst,\r
1258         const NyLPC_TcIPv4Payload_t* i_ipp)\r
1259 {\r
1260         int i,s;\r
1261         NyLPC_TUInt16 tmp16;\r
1262         NyLPC_TUInt16 data_size;\r
1263         NyLPC_TUInt8 in_tcpflag=i_ipp->payload.tcp->flags;\r
1264         const void* tcp_data_offset;\r
1265         NyLPC_TBool is_new_packet;\r
1266         int num_of_noack;\r
1267         void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];\r
1268         void* ret;\r
1269 \r
1270         //パラメータの計算\r
1271 \r
1272         tmp16=NyLPC_TTcpHeader_getHeaderLength(i_ipp->payload.tcp);\r
1273         //TCPペイロードの長さは、IPパケットの長さ-(IPヘッダ+TCPヘッダ)\r
1274         data_size=NyLPC_TIPv4Header_getPacketLength(i_ipp->header)-NyLPC_TIPv4Header_getHeaderLength(i_ipp->header)-tmp16;\r
1275         //TCPデータオフセット\r
1276         tcp_data_offset=i_ipp->payload.rawbuf+tmp16;\r
1277 \r
1278         //インスタンスをロックする。\r
1279         lockResource(i_inst);\r
1280 \r
1281         //RSTのチェック。RST受信時は、状態にかかわらず、CLOSEDステータスに移行する。\r
1282         if (in_tcpflag & TCP_RST)\r
1283         {\r
1284                 i_inst->tcpstateflags =UIP_CLOSED;\r
1285                 goto DROP;\r
1286         }\r
1287 \r
1288 \r
1289         is_new_packet=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)==i_inst->uip_connr.rcv_nxt32;\r
1290 \r
1291 \r
1292         //OPTIONの反映\r
1293 \r
1294         //MSSの取得\r
1295         if(NyLPC_TTcpHeader_getTcpMmsOpt(i_ipp->payload.tcp,&tmp16)){\r
1296                 //取得で着たら更新\r
1297                 i_inst->uip_connr.peer_mss=tmp16;\r
1298         }\r
1299         //受信パケットを元に、未ACKパケットの数を計算\r
1300         num_of_noack=getNumOfSending(i_inst,i_ipp->payload.tcp->ackno32);//i_inst->txbuf.num_of_txq;\r
1301 \r
1302         //ステータス毎のACK応答\r
1303         switch(i_inst->tcpstateflags)\r
1304         {\r
1305         case UIP_SYN_RCVD:\r
1306                 //ACKを受信したら、ESTABLISHEDへ。\r
1307                 //すべてのパケットをACKしたかで判定。()\r
1308                 if(num_of_noack==0){\r
1309                         i_inst->tcpstateflags=UIP_ESTABLISHED;\r
1310                 }else{\r
1311                         //それ以外のパケットはドロップする。\r
1312                         break;//goto DROP;\r
1313                 }\r
1314                 //新しいパケットがなければ、無応答\r
1315                 if(!is_new_packet){\r
1316                         break;//goto DROP;\r
1317                 }\r
1318                 //引き続き、ESTABLISHEDの処理へ。\r
1319         case UIP_ESTABLISHED:\r
1320                 if(data_size>0){\r
1321                         if(is_new_packet){\r
1322                                 if(addRecvData(i_inst,tcp_data_offset,data_size)){\r
1323                                         //通常のACK返却\r
1324                                         i_inst->uip_connr.rcv_nxt32+=data_size;\r
1325                                 }else{\r
1326                                         //失敗したときは必要に応じて単純ACK\r
1327                                 }\r
1328                         }\r
1329                 }\r
1330                 //どちらにしろ、ACK送信\r
1331                 if(is_new_packet && (in_tcpflag & TCP_FIN)){\r
1332                         //FINがあるときは、ステータスをCLOSE_WAITへセットして、ACKを返す。\r
1333                         i_inst->tcpstateflags = UIP_CLOSE_WAIT;\r
1334                         i_inst->uip_connr.rcv_nxt32++;\r
1335                 }\r
1336                 break;\r
1337         case UIP_CLOSE_WAIT:\r
1338                 //必要に応じたACK応答\r
1339                 break;\r
1340         case UIP_LAST_ACK:\r
1341                 //ACK(by FIN)が得られたなら、CLOSEDへ。\r
1342                 if(num_of_noack==0){\r
1343                         i_inst->tcpstateflags=UIP_CLOSED;\r
1344                 }\r
1345                 //必要に応じたACK応答\r
1346                 break;\r
1347         case UIP_FIN_WAIT_1:\r
1348                 //FIN受信->CLOSINGへ\r
1349                 if(is_new_packet){\r
1350                         i_inst->uip_connr.rcv_nxt32+=data_size;\r
1351                         if(in_tcpflag & TCP_FIN){\r
1352                                 i_inst->uip_connr.rcv_nxt32++;\r
1353                                 if(num_of_noack==0){\r
1354                                         //FINとACKを受信\r
1355                                         i_inst->tcpstateflags=UIP_TIME_WAIT;\r
1356                                 }else{\r
1357                                         //FINのみ\r
1358                                         i_inst->tcpstateflags=UIP_CLOSING;\r
1359                                 }\r
1360                         }\r
1361                 }else if(num_of_noack==0){\r
1362                         //ACKのみ\r
1363                         i_inst->tcpstateflags=UIP_FIN_WAIT_2;\r
1364                 }\r
1365                 //必要に応じたACK応答\r
1366                 break;\r
1367         case UIP_FIN_WAIT_2:\r
1368                 //FIN受信->TIME_WAITへ(pureACK)\r
1369                 if(is_new_packet && (in_tcpflag & TCP_FIN)){\r
1370                         i_inst->uip_connr.rcv_nxt32++;\r
1371                         i_inst->tcpstateflags=UIP_TIME_WAIT;\r
1372                 }\r
1373                 break;\r
1374         case UIP_CLOSING:\r
1375                 //ACK受信したら、TIME_WAITへ\r
1376                 if(num_of_noack==0){\r
1377                         i_inst->tcpstateflags=UIP_TIME_WAIT;\r
1378                 }\r
1379                 break;\r
1380         case UIP_CLOSED:\r
1381                 //何もできない。何もしない。\r
1382                 break;\r
1383         case UIP_TIME_WAIT:\r
1384                 //最終ACKを送り続ける。\r
1385                 break;\r
1386         case UIP_SYN_SENT:\r
1387                 //connect関数実行中しか起動しないステータス\r
1388                 if(num_of_noack==0){\r
1389                         i_inst->tcpstateflags=UIP_ESTABLISHED;\r
1390                         i_inst->uip_connr.rcv_nxt32=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)+1;\r
1391                 }else{\r
1392                         //それ以外のパケットはドロップする。\r
1393                         break;//goto DROP;\r
1394                 }\r
1395                 //ACKを送る。\r
1396                 break;\r
1397         default:\r
1398                 goto DROP;\r
1399         }\r
1400         //ウインドウサイズを更新\r
1401         i_inst->uip_connr.peer_win=NyLPC_ntohs(i_ipp->payload.tcp->wnd16);\r
1402 \r
1403         //送信キューから、Peerが受信したデータを削除する。\r
1404         if(in_tcpflag & TCP_ACK){\r
1405                 //再送パケットキューから送信済みのデータを回収(後で開放)\r
1406                 NyLPC_Trace();\r
1407                 s=updateTxQByIndex(i_inst,i_ipp->payload.tcp->ackno32,dlist);\r
1408                 NyLPC_Trace();\r
1409         }else{\r
1410                 s=0;\r
1411         }\r
1412         //新しいパケットがきた場合は、再送キューのACKを更新する。\r
1413         if(is_new_packet){\r
1414                 //再送キューのACKを更新\r
1415                 updateTxAck(i_inst,NyLPC_htonl(i_inst->uip_connr.rcv_nxt32));\r
1416         }\r
1417 \r
1418         //送信キューのない\r
1419         if(((in_tcpflag&(TCP_FIN|TCP_SYN))!=0x00) ||\r
1420                 ((!is_new_packet) && (data_size>0)))\r
1421         {\r
1422                 //ソケットからPureACKを生成 as setPacket(i_inst,i_ipp,TCP_ACK,NULL,0);\r
1423                 ret=NyLPC_cUipService_allocSysTxBuf();\r
1424                 setTxPacket(i_inst,ret,TCP_ACK,NULL,0);\r
1425         }else{\r
1426                 ret=NULL;\r
1427         }\r
1428         unlockResource(i_inst);\r
1429         //取り外したTXメモリの開放\r
1430         for(i=0;i<s;i++){\r
1431                 //取り外したTXメモリを開放\r
1432                 NyLPC_cUipService_releaseTxBuf(dlist[i]);\r
1433         }\r
1434 NyLPC_Trace();\r
1435         return ret;\r
1436 DROP:\r
1437         //ACKしたパケットを送信キューから削除\r
1438         unlockResource(i_inst);\r
1439 NyLPC_Trace();\r
1440         return NULL;\r
1441 }\r
1442 \r
1443 \r
1444 /**\r
1445  * 入力されたパケットからRSTパケットを生成して返す。\r
1446  */\r
1447 void* NyLPC_cTcpSocket_allocTcpReverseRstAck(\r
1448         const NyLPC_TcIPv4Payload_t* i_src)\r
1449 {\r
1450         struct NyLPC_TIPv4Header*       iph;\r
1451         struct NyLPC_TTcpHeader*        tcph;\r
1452         NyLPC_TUInt8 iph_word=0x05;\r
1453         NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;\r
1454         void* txb=NyLPC_cUipService_allocSysTxBuf();\r
1455         //IPヘッダの更新\r
1456         iph=(struct NyLPC_TIPv4Header*)txb;\r
1457         iph->vhl=0x40|(0x0f&iph_word);\r
1458         iph->destipaddr=i_src->header->srcipaddr;\r
1459         iph->srcipaddr =i_src->header->destipaddr;\r
1460         NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);\r
1461 \r
1462         //TCPヘッダの更新\r
1463         tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)txb)+NyLPC_TIPv4Header_getHeaderLength(iph));\r
1464 \r
1465         tcph->tcpoffset=(tcph_word<<4);\r
1466 \r
1467         tcph->flags    = TCP_RST | TCP_ACK;\r
1468         //sorce & destination port\r
1469         tcph->srcport  = i_src->payload.tcp->destport;\r
1470         tcph->destport = i_src->payload.tcp->srcport;\r
1471         //ACK number\r
1472         tcph->ackno32  = NyLPC_htonl(NyLPC_ntohl(i_src->payload.tcp->seqno32)+1);\r
1473         //Seq Number\r
1474         tcph->seqno32  = i_src->payload.tcp->ackno32;\r
1475         //uip_func_tcp_send_noconn(BUF);\r
1476         tcph->urgp[0]  = tcph->urgp[1] = 0;\r
1477         tcph->tcpchksum= 0;\r
1478 \r
1479 \r
1480         //最終的なパケットサイズと必要ならペイロードを書き込み\r
1481         iph->len16=NyLPC_htons((iph_word+tcph_word)*4);\r
1482         //WND設定\r
1483         tcph->wnd16=0;\r
1484         //Checksumの生成\r
1485         tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));\r
1486         iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));\r
1487         return txb;\r
1488 }\r
1489 \r
1490 \r
1491 \r
1492 \r