OSDN Git Service

APIPAの為のAPI追加
[mimic/MiMicSDK.git] / lib / src / uip / NyLPC_cUipService.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  * Parts of this file were leveraged from uIP:\r
27  *\r
28  * Copyright (c) 2001-2003, Adam Dunkels.\r
29  * All rights reserved.\r
30  *\r
31  * Redistribution and use in source and binary forms, with or without\r
32  * modification, are permitted provided that the following conditions\r
33  * are met:\r
34  * 1. Redistributions of source code must retain the above copyright\r
35  *    notice, this list of conditions and the following disclaimer.\r
36  * 2. Redistributions in binary form must reproduce the above copyright\r
37  *    notice, this list of conditions and the following disclaimer in the\r
38  *    documentation and/or other materials provided with the distribution.\r
39  * 3. The name of the author may not be used to endorse or promote\r
40  *    products derived from this software without specific prior\r
41  *    written permission.\r
42  *\r
43  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
44  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
45  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
46  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
47  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
48  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
49  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
50  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
51  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
52  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
53  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
54  */\r
55 #include "NyLPC_cIPv4IComp_protected.h"\r
56 #include "NyLPC_cTcpListener_protected.h"\r
57 #include "NyLPC_stdlib.h"\r
58 #include "NyLPC_uip.h"\r
59 \r
60 \r
61 \r
62 \r
63 \r
64 /****************************************************\r
65  * UipServiceに関する宣言:タスクメッセージ\r
66  ***************************************************/\r
67 \r
68 #define TTaskMsg_NOP 0\r
69 #define TTaskMsg_START 1\r
70 #define TTaskMsg_STOP 2\r
71 \r
72 /**\r
73  * サービスの起動メッセージです。\r
74  */\r
75 struct TTaskMsg{\r
76         NyLPC_TUInt16 msg;\r
77         union{\r
78                 struct{\r
79                         const NyLPC_TcIPv4Config_t* ref_config;\r
80                 }start;\r
81         };\r
82 };\r
83 \r
84 /****************************************************\r
85  * UipServiceに関する宣言:その他\r
86  ***************************************************/\r
87 /**\r
88  * イーサネットフレームの読み出し構造体\r
89  */\r
90 struct TEthPacket\r
91 {\r
92         struct NyLPC_TEthernetIIHeader header;\r
93         union{\r
94                 struct NyLPC_TArpHeader arp;\r
95                 struct NyLPC_TIPv4Header ipv4;\r
96         }data;\r
97 };\r
98 \r
99 \r
100 \r
101 /**\r
102  * サービスインスタンスのポインタ。サービスが稼働中はインスタンスのポインタが有効です。
103  */\r
104 NyLPC_TcUipService_t* _NyLPC_TcUipService_inst=NULL;\r
105 \r
106 /**\r
107  * 唯一のインスタンス
108  */\r
109 static NyLPC_TcUipService_t _service_instance;\r
110 \r
111 \r
112 \r
113 \r
114 /**\r
115  * uipタスク
116  */\r
117 static int uipTask(void *pvParameters);\r
118 \r
119 //--------------------------------------------------------------\r
120 \r
121 \r
122 static NyLPC_TBool sendIPv4Tx(struct NyLPC_TTxBufferHeader* i_eth_buf);\r
123 static void copyAndSendIPv4Tx(const struct TEthPacket* i_buf);\r
124 static void sendArpReqest(const struct TEthPacket* i_eth_packet);\r
125 static void sendRawEthFrame(void* i_buf,NyLPC_TUInt16 i_len);\r
126 static void emacIsrHandler(unsigned long i_status);\r
127 \r
128 /**メッセージなし*/\r
129 #define TTaskMessage_MSG_NULL    0x0000\r
130 /**uipコアタスクに、開始要求する*/\r
131 #define TTaskMessage_MSG_RUN     0x0001\r
132 /**uipコアタスクに、停止要求する*/\r
133 #define TTaskMessage_MSG_STOP    0x0002\r
134 \r
135 \r
136 NyLPC_TcThread_t th;\r
137 \r
138 NyLPC_TBool NyLPC_cUipService_initialize(void)\r
139 {\r
140         NyLPC_TcUipService_t* inst=&_service_instance;\r
141         //サービスは停止している事。 - Service must be uninitialized.\r
142         NyLPC_Assert(!NyLPC_TcUipService_isInitService());\r
143         //IP処理部分の初期化\r
144         NyLPC_cIPv4_initialize(&(inst->_tcpv4));\r
145         //EMACからの割込処理\r
146         NyLPC_cIsr_setEnetISR(emacIsrHandler);\r
147         //EMAC割込セマフォ\r
148         NyLPC_cSemaphore_initialize(&inst->_emac_semapho);\r
149 \r
150         inst->_task_cmd=NULL;\r
151         inst->_status=NyLPC_TcUipService_STATUS_STOP;\r
152         NyLPC_cStopwatch_initialize(&(inst->_arp_sw));\r
153         NyLPC_cStopwatch_initialize(&(inst->_periodic_sw));\r
154         NyLPC_cIPv4_initialize(&(inst->_tcpv4));\r
155         NyLPC_AbortIfNot(NyLPC_cMutex_initialize(&(inst->_mutex)));\r
156 \r
157         _NyLPC_TcUipService_inst=inst;\r
158         inst->stx.h.is_lock=NyLPC_TUInt8_FALSE;\r
159         inst->stx.h.ref=0;\r
160         //タスク起動\r
161         NyLPC_cThread_initialize(&th,NyLPC_TcUipService_config_STACK_SIZE,NyLPC_TcThread_PRIORITY_SERVICE);\r
162         NyLPC_cThread_start(&th,uipTask,NULL);\r
163         return NyLPC_TBool_TRUE;\r
164 }\r
165 \r
166 \r
167 \r
168 \r
169 \r
170 \r
171 \r
172 /**\r
173  * UIP処理を開始します。\r
174  * この関数はリエントラントではありません。複数のタスクから共有するときには、排他ロックを掛けてください。\r
175  * @param i_ref_config\r
176  * このコンフィギュレーションは、stopを実行するまでの間、インスタンスから参照します。外部で保持してください。\r
177  */\r
178 void NyLPC_cUipService_start(const NyLPC_TcIPv4Config_t* i_ref_config)\r
179 {\r
180         NyLPC_TcUipService_t* inst=&_service_instance;\r
181         struct TTaskMsg msg;\r
182         NyLPC_Assert(NyLPC_TcUipService_isInitService());\r
183         if(!NyLPC_cUipService_isRun())\r
184         {\r
185                 //はじめて起動するときに1度だけデバイス取得(タスクスイッチが動いてないと動かないからここで。)\r
186                 if(inst->_ethif==NULL){\r
187                         inst->_ethif=getEthernetDevicePnP();\r
188                 }\r
189                 //コマンドセット\r
190                 msg.msg=TTaskMsg_START;\r
191                 msg.start.ref_config=i_ref_config;\r
192                 _NyLPC_TcUipService_inst->_task_cmd=&msg;\r
193                 //状態が変わるまでループ\r
194                 while(!NyLPC_cUipService_isRun()){\r
195                         NyLPC_cThread_sleep(10);\r
196                 }\r
197         }\r
198         //コマンドクリア\r
199         _NyLPC_TcUipService_inst->_task_cmd=NULL;\r
200         return;\r
201 }\r
202 /**\r
203  * UIP処理を停止します。\r
204  * この関数はリエントラントではありません。複数のタスクから共有するときには、排他ロックを掛けてください。\r
205  * いまのところ、ストップシーケンスの実装は良くありません。\r
206  * 再設計が必要。
207  */\r
208 void NyLPC_cUipService_stop(void)\r
209 {\r
210         struct TTaskMsg msg;\r
211         NyLPC_TcUipService_t* inst=&_service_instance;\r
212         NyLPC_Assert(NyLPC_TcUipService_isInitService());\r
213         if(NyLPC_cUipService_isRun())\r
214         {\r
215                 //コマンドセット\r
216                 msg.msg=TTaskMsg_STOP;\r
217                 _NyLPC_TcUipService_inst->_task_cmd=&msg;\r
218                 //状態が変わるまでループ\r
219                 while(NyLPC_cUipService_isRun()){\r
220                         NyLPC_cThread_sleep(10);\r
221                 }\r
222                 NyLPC_cIPv4_stop(&(inst->_tcpv4));\r
223 \r
224         }\r
225         //コマンドクリア\r
226         _NyLPC_TcUipService_inst->_task_cmd=NULL;\r
227         return;\r
228 }\r
229 \r
230 \r
231 const char* NyLPC_cUipService_refDeviceName(void)\r
232 {\r
233         NyLPC_TcUipService_t* inst=&_service_instance;\r
234         return NyLPC_cUipService_isRun()?inst->_ethif->device_name:NULL;\r
235 }\r
236 const NyLPC_TcIPv4Config_t* NyLPC_cUipService_refCurrentConfig(void)\r
237 {\r
238         NyLPC_TcUipService_t* inst=&_service_instance;\r
239         return inst->_ref_config;\r
240 }\r
241 /**********************************************************************\r
242  *\r
243  * </HWコールバックに関わる宣言>\r
244  *\r
245  *********************************************************************/\r
246 \r
247 /**\r
248  * EMACからのハンドラ\r
249  */\r
250 static void emacIsrHandler(unsigned long i_status)\r
251 {\r
252         NyLPC_TcUipService_t* inst=&_service_instance;\r
253 \r
254         if( i_status & INT_RX_DONE )\r
255         {\r
256                 //受信系のセマフォブロックの解除\r
257                 NyLPC_cSemaphore_giveFromISR(&inst->_emac_semapho);\r
258         }\r
259         if( i_status & INT_TX_DONE )\r
260         {\r
261         }\r
262 }\r
263 \r
264 \r
265 //PERIODIC rate\r
266 #define PERIODIC_TIMER (1*200)\r
267 #define ARP_TIMER (60*1000*10)\r
268 \r
269 \r
270 \r
271 /**\r
272  * 操作キューを確認して、タスクのステータスをアップデートします。\r
273  * 高速化のため、Proc-Callerを使用していません。複雑なタスク操作をするときには、書き換えてください。
274  */\r
275 static void updateTaskStatus()\r
276 {\r
277         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
278 \r
279         struct TTaskMsg* msg=(struct TTaskMsg*)(inst->_task_cmd);\r
280 \r
281         //コマンドが設定されていない時は、何もしない。\r
282         if(msg==NULL){\r
283                 return;\r
284         }\r
285         switch(msg->msg)\r
286         {\r
287         //何もしない。\r
288         case TTaskMsg_NOP:\r
289                 break;\r
290         //開始操作\r
291         case TTaskMsg_START:\r
292                 //状態チェック\r
293                 if(NyLPC_cUipService_isRun()){\r
294                         break;\r
295                 }\r
296                 inst->_ref_config=msg->start.ref_config;\r
297                 //TCP,ICOMPの初期化\r
298                 NyLPC_cIPv4_start(&(inst->_tcpv4),inst->_ref_config);\r
299                 NyLPC_cIPv4IComp_initialize(&(inst->_icomp),inst->_ref_config);\r
300                 //uip_arp_init(msg->start.ref_config);\r
301                 NyLPC_cIPv4Arp_initialize(&(inst->_arp),inst->_ref_config);\r
302                 NyLPC_cStopwatch_startExpire(&(inst->_arp_sw),1);//1度ARPを起動するため。\r
303                 NyLPC_cStopwatch_startExpire(&(inst->_periodic_sw),PERIODIC_TIMER);\r
304                 while(!inst->_ethif->start(&(inst->_ref_config->eth_mac)));\r
305                 inst->_status=NyLPC_TcUipService_STATUS_RUN;\r
306                 break;\r
307         //終了操作\r
308         case TTaskMsg_STOP:\r
309                 //状態チェック\r
310                 if(!NyLPC_cUipService_isRun()){\r
311                         break;\r
312                 }\r
313                 //停止操作\r
314                 inst->_ethif->stop();\r
315                 NyLPC_cIPv4_stop(&(inst->_tcpv4));\r
316                 NyLPC_cIPv4IComp_finalize(&(inst->_icomp));\r
317                 NyLPC_cIPv4Arp_finalize(&(inst->_arp));\r
318                 inst->_status=NyLPC_TcUipService_STATUS_STOP;\r
319                 break;\r
320         default:\r
321                 //実行してはいけない。\r
322                 NyLPC_Abort();\r
323         }\r
324         //コマンドを無効化\r
325         inst->_task_cmd=TTaskMsg_NOP;\r
326         return;\r
327 }\r
328 \r
329 /**\r
330  * uipタスクのメインループ
331  */\r
332 static int uipTask(void *pvParameters)\r
333 {\r
334         NyLPC_TUInt16 rx_len,tx_len;\r
335         struct TEthPacket* ethbuf;\r
336         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
337         NyLPC_TBool r;\r
338         (void)pvParameters;\r
339         for( ;; )\r
340         {\r
341                 //タスク状態の更新\r
342                 updateTaskStatus();\r
343                 if(inst->_status!=NyLPC_TcUipService_STATUS_RUN)\r
344                 {\r
345                         //RUNステータス以外の時は、ここで終了する。\r
346                         NyLPC_cThread_sleep(50);\r
347                         continue;\r
348                 }\r
349                 //イーサネットフレームの取得\r
350                 //Ethernet Device Lock(ARPを含む)\r
351                 NyLPC_cMutex_lock(&(inst->_mutex));\r
352                 ethbuf= (struct TEthPacket*)inst->_ethif->getRxEthFrame(&rx_len);\r
353                 tx_len=0;\r
354                 while(ethbuf != NULL){\r
355                         if(rx_len>0)\r
356                         {\r
357                                 //ペイロードサイズを計算\r
358                                 rx_len-=sizeof(struct NyLPC_TEthernetIIHeader);\r
359                                 switch(ethbuf->header.type)\r
360                                 {\r
361                                 case NyLPC_HTONS(NyLPC_TEthernetIIHeader_TYPE_IP):\r
362                                         //ARPテーブルの更新\r
363                                         //uip_arp_ipin(&(ethbuf->header),ethbuf->data.ipv4.srcipaddr);\r
364                                         NyLPC_cIPv4Arp_incomingIp(&inst->_arp,&(ethbuf->header),ethbuf->data.ipv4.srcipaddr);\r
365                                         //Ethernet Device UnLock(パケット解析の為に一時的な解除)\r
366                                         NyLPC_cMutex_unlock(&(inst->_mutex));\r
367                                         //IPパケットの処理\r
368                                         r=NyLPC_cIPv4_rx(&(inst->_tcpv4),&(ethbuf->data.ipv4),rx_len);\r
369                                         //ロックの復帰\r
370                                         NyLPC_cMutex_lock(&(inst->_mutex));\r
371                                         if(!r){\r
372                                                 //応答データは存在しない。\r
373                                                 break;\r
374                                         }\r
375                                         //IPパケットをTxバッファに転写して送信\r
376                                         copyAndSendIPv4Tx(ethbuf);\r
377                                         ethbuf=NULL;\r
378                                         break;\r
379                                 case NyLPC_HTONS(NyLPC_TEthernetIIHeader_TYPE_ARP):\r
380                                         //if(uip_arp_arpin(&(ethbuf->data.arp),rx_len)){\r
381                                         if(NyLPC_cIPv4Arp_incomingArp(&inst->_arp,&(ethbuf->data.arp),rx_len)){\r
382                                                 tx_len=NyLPC_TEthernetIIHeader_setArpTx(&(ethbuf->header),&(inst->_ref_config->eth_mac));\r
383                                         }\r
384                                         if(tx_len>0){\r
385                                                 sendRawEthFrame(ethbuf,tx_len);\r
386                                         }\r
387                                         break;\r
388                                 case NyLPC_HTONS(NyLPC_TEthernetIIHeader_TYPE_IPV6):\r
389                                         //uip_process_ipv6();\r
390                                         break;\r
391                                 default:\r
392                                         break;\r
393                                 }\r
394                         }\r
395                         //受信キューを進行。\r
396                         inst->_ethif->nextRxEthFrame();\r
397                         //受信処理\r
398                         ethbuf= (struct TEthPacket*)inst->_ethif->getRxEthFrame(&rx_len);\r
399                 }\r
400                 //データが無い。\r
401                 if(NyLPC_cStopwatch_isExpired(&(inst->_arp_sw))){\r
402                         //uip_arp_timer();\r
403                         NyLPC_cIPv4Arp_periodic(&inst->_arp);\r
404                         NyLPC_cStopwatch_startExpire(&(inst->_arp_sw),ARP_TIMER);\r
405                 }\r
406                 if(NyLPC_cStopwatch_isExpired(&(inst->_periodic_sw))){\r
407                         NyLPC_cIPv4_periodec(&(inst->_tcpv4));\r
408                         NyLPC_cStopwatch_startExpire(&(inst->_periodic_sw),PERIODIC_TIMER);\r
409                 }\r
410                 //リソースロックの解除\r
411                 NyLPC_cMutex_unlock(&(inst->_mutex));\r
412                 //割込によるセマフォの解除か、タイムアウトで再開する。(タイムアウト値は周期関数の実行レート以下にすること。)\r
413                 NyLPC_cSemaphore_take(&(_NyLPC_TcUipService_inst->_emac_semapho),PERIODIC_TIMER);\r
414         }\r
415         return 0;\r
416 }\r
417 \r
418 \r
419 \r
420 \r
421 /**\r
422  * allocTxBufで取得したメモリを"IPパケットとして"送信します。\r
423  * @param i_eth_payload\r
424  * [NyLPC_TTxBufferHeader][NyLPC_TEthernetIIHeader][payload]メモリの、[payload]のアドレスを指定します。\r
425  * 通常は、NyLPC_cUipService_allocTxBufの返却したメモリを指定します。\r
426  */\r
427 \r
428 void NyLPC_cUipService_sendIPv4Tx(void* i_eth_payload)\r
429 {\r
430         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
431         NyLPC_cMutex_lock(&(inst->_mutex));\r
432         //IPパケットの送信を試行\r
433         if(!sendIPv4Tx(((struct NyLPC_TTxBufferHeader*)(((struct NyLPC_TEthernetIIHeader*)i_eth_payload)-1))-1)){\r
434                 //ARPリクエストを代わりに送信\r
435                 sendArpReqest(((struct TEthPacket*)i_eth_payload)-1);\r
436         }\r
437         NyLPC_cMutex_unlock(&(inst->_mutex));\r
438         return;\r
439 }\r
440 /**\r
441  * 指定したIPアドレスに対してARPRequestを送信します。\r
442  */\r
443 void NyLPC_cUipService_sendArpRequest(const struct NyLPC_TIPv4Addr* i_addr)\r
444 {\r
445         void* buf;\r
446         struct TEthPacket* ethbuf;\r
447         NyLPC_TUInt16 s;\r
448         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
449         NyLPC_TUInt16 tx_len;\r
450         do{\r
451                 buf=NyLPC_cUipService_allocTxBuf(64,&s);\r
452                 NyLPC_cThread_sleep(10);\r
453         }while(buf==NULL);\r
454         //IPパケットのアドレスをイーサネットパケットアドレスまで後退させる。\r
455         ethbuf=(struct TEthPacket*)(((struct NyLPC_TEthernetIIHeader*)buf)-1);\r
456         //ARPパケットを作る。\r
457         NyLPC_TArpHeader_setArpRequest(&(ethbuf->data.arp),inst->_ref_config->ip_addr,&(inst->_ref_config->eth_mac),*i_addr);\r
458         tx_len=NyLPC_TEthernetIIHeader_setArpTx(&(ethbuf->header),&(inst->_ref_config->eth_mac));\r
459         //送信\r
460         NyLPC_cMutex_lock(&(inst->_mutex));\r
461         inst->_ethif->sendTxEthFrame(((struct NyLPC_TTxBufferHeader*)ethbuf)-1,tx_len);\r
462         NyLPC_cMutex_unlock(&(inst->_mutex));\r
463         return;\r
464 }\r
465 \r
466 /**\r
467  * ARPテーブルに指定したIPがあるかを返します。\r
468  */\r
469 NyLPC_TBool NyLPC_cUipService_hasArpInfo(const struct NyLPC_TIPv4Addr* i_addr)\r
470 {\r
471         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
472         return NyLPC_cIPv4Arp_IPv4toEthAddr(&inst->_arp,*i_addr)!=NULL;\r
473 }\r
474 \r
475 \r
476 /**\r
477  * 送信ペイロードメモリを返します。\r
478  * この関数は、リエントラントを許容します。\r
479  * @param i_hint\r
480  * 取得したいメモリサイズを指定します。(このサイズは、イーサネットヘッダのサイズを含みません。)\r
481  * このサイズよりも小さなサイズが割り当てられることがあります。\r
482  * @param o_size\r
483  * イーサネットヘッダを除いたペイロード部分の長さ\r
484  * @return\r
485  * 成功:IPペイロードのためのメモリブロックを返します。/失敗:NULL\r
486  * 返されるメモリはブロックの[TEthPacket][payload]の構造で、[payload]のアドレスが返されます。
487  */\r
488 void* NyLPC_cUipService_allocTxBuf(NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_size)\r
489 {\r
490         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
491         struct NyLPC_TTxBufferHeader* ethbuf;\r
492         //排他処理をして、メモリを取得する。\r
493         NyLPC_cMutex_lock(&(inst->_mutex));\r
494         ethbuf=(struct NyLPC_TTxBufferHeader*)inst->_ethif->allocTxBuf(i_hint+sizeof(struct NyLPC_TEthernetIIHeader),o_size);\r
495         NyLPC_cMutex_unlock(&(inst->_mutex));\r
496         if(ethbuf==NULL){\r
497                 return NULL;\r
498         }\r
499         //イーサネットバッファのサイズを計算\r
500         *o_size-=sizeof(struct NyLPC_TEthernetIIHeader);\r
501         //イーサネットバッファのアドレスを計算\r
502         return &(((struct TEthPacket*)(ethbuf+1))->data);\r
503 }\r
504 \r
505 \r
506 void* NyLPC_cUipService_releaseTxBuf(void* i_buf)\r
507 {\r
508         //排他処理をして、メモリを開放する。\r
509         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
510         NyLPC_cMutex_lock(&(inst->_mutex));\r
511         //ペイロードの位置から、メモリブロックを再生。\r
512         inst->_ethif->releaseTxBuf(((struct NyLPC_TTxBufferHeader*)(((struct NyLPC_TEthernetIIHeader*)i_buf)-1))-1);\r
513         NyLPC_cMutex_unlock(&(inst->_mutex));\r
514         return NULL;\r
515 }\r
516 \r
517 \r
518 \r
519 \r
520 \r
521 \r
522 \r
523 \r
524 /**********\r
525  * イーサネットHWのコントロール関数\r
526  */\r
527 \r
528 /**\r
529  * 新たにメモリを確保して、"IPv4パケットを格納した"イーサフレームを送信します。\r
530  * コール前に、必ずロックしてから呼び出してください。\r
531  */\r
532 static void copyAndSendIPv4Tx(const struct TEthPacket* i_buf)\r
533 {\r
534         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
535         NyLPC_TUInt16 s;\r
536         //ACK送信用の自己バッファが空くまで待つ\r
537         while(inst->stx.h.is_lock){\r
538                 inst->_ethif->processTx();\r
539         }\r
540         //送信する。\r
541         s=NyLPC_htons(i_buf->data.ipv4.len16)+sizeof(struct NyLPC_TEthernetIIHeader);\r
542         memcpy(inst->stx.buf,i_buf,s);\r
543         if(!sendIPv4Tx(&(inst->stx.h))){\r
544                 //失敗した場合はARPリクエストに変換して再送\r
545                 sendArpReqest(i_buf);\r
546         }\r
547         return;\r
548 }\r
549 /**\r
550  * IPv4パケットのpeerIPを問い合わせるARPパケットを送信します。\r
551  */\r
552 static void sendArpReqest(const struct TEthPacket* i_eth_packet)\r
553 {\r
554         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
555         NyLPC_TUInt16 tx_len;\r
556         struct TEthPacket* ethbuf;\r
557         //ACK送信用の自己バッファが空くまで待つ\r
558         while(inst->stx.h.is_lock){\r
559                 inst->_ethif->processTx();\r
560         }\r
561         //ARPパケットを作る。\r
562         ethbuf=(struct TEthPacket*)(inst->stx.buf);\r
563         NyLPC_TArpHeader_setArpRequest(&(ethbuf->data.arp),inst->_ref_config->ip_addr,&(inst->_ref_config->eth_mac),i_eth_packet->data.ipv4.destipaddr);\r
564         tx_len=NyLPC_TEthernetIIHeader_setArpTx(&(ethbuf->header),&(inst->_ref_config->eth_mac));\r
565         //送信\r
566         inst->_ethif->sendTxEthFrame(&(inst->stx.h),tx_len);\r
567 }\r
568 \r
569 /**\r
570  * uipタスクが所有するTXバッファを使用してデータを送信します。\r
571  * この関数は、i_bufをコピーします。\r
572  * @i_buf\r
573  * イーサネットフレームを格納したメモリです。\r
574  * @i_len\r
575  * イーサネットペイロードのサイズです。\r
576  */\r
577 static void sendRawEthFrame(void* i_buf,NyLPC_TUInt16 i_len)\r
578 {\r
579         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
580 \r
581         //ACK送信用の自己バッファが空くまで待つ\r
582         while(inst->stx.h.is_lock){\r
583                 inst->_ethif->processTx();\r
584         }\r
585         //64バイトを超えるとかありえない。\r
586         if(i_len+sizeof(struct NyLPC_TEthernetIIHeader)>NyLPC_TcUipService_SIZE_OF_REPLY_BUF){\r
587                 return;\r
588         }\r
589         //送信する。\r
590         memcpy(inst->stx.buf,i_buf,i_len);\r
591         inst->_ethif->sendTxEthFrame(&(inst->stx.h),i_len);\r
592         return;\r
593 }\r
594 \r
595 /**\r
596  * マルチキャスとアドレスへ変換する。\r
597  */\r
598 static void ip2MulticastEmacAddr(const struct NyLPC_TIPv4Addr* i_addr,struct NyLPC_TEthAddr* o_emac)\r
599 {\r
600         NyLPC_TUInt32 n=NyLPC_htonl(i_addr->v);\r
601         o_emac->addr[0]=0x01;\r
602         o_emac->addr[1]=0x00;\r
603         o_emac->addr[2]=0x5E;\r
604         o_emac->addr[3]=((n>>16) & 0x7f);\r
605         o_emac->addr[4]=((n>> 8) & 0xff);\r
606         o_emac->addr[5]=(n & 0xff);\r
607         return;\r
608 };\r
609 \r
610 /**\r
611  * ペイロードをIPパケットとしてネットワークへ送出します。\r
612  * コール前に、必ずロックしてから呼び出してください。\r
613  * @param i_eth_payload\r
614  * allocTxBufで確保したメモリを指定してください。\r
615  * ペイロードには、TCP/IPパケットを格納します。\r
616  */\r
617 static NyLPC_TBool sendIPv4Tx(struct NyLPC_TTxBufferHeader* i_eth_buf)\r
618 {\r
619         NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
620         struct NyLPC_TEthAddr emac;\r
621         NyLPC_TUInt16 tx_len;\r
622         const struct NyLPC_TEthAddr* eth_dest;\r
623         struct TEthPacket* ethbuf=(struct TEthPacket*)(i_eth_buf+1);\r
624         //ペイロードのアドレスから、イーサネットフレームバッファのアドレスを復元\r
625 \r
626         if(NyLPC_TIPv4Addr_isEqual(&(ethbuf->data.ipv4.destipaddr),&NyLPC_TIPv4Addr_BROADCAST)) {\r
627                 //ブロードキャストならそのまま\r
628                 eth_dest=&NyLPC_TEthAddr_BROADCAST;\r
629         }else if(NyLPC_TIPv4Addr_isEqualWithMask(&(ethbuf->data.ipv4.destipaddr),&NyLPC_TIPv4Addr_MULTICAST,&NyLPC_TIPv4Addr_MULTICAST_MASK)){\r
630                 //マルチキャスト\r
631                 ip2MulticastEmacAddr(&(ethbuf->data.ipv4.destipaddr),&emac);\r
632                 eth_dest=&emac;\r
633         }else{\r
634                 //LocalIP以外ならdefaultRootへ変換\r
635                 eth_dest=NyLPC_cIPv4Arp_IPv4toEthAddr(\r
636                         &inst->_arp,\r
637                         NyLPC_cIPv4Config_isLocalIP(inst->_ref_config, &(ethbuf->data.ipv4.destipaddr))?(ethbuf->data.ipv4.destipaddr):(inst->_ref_config->dr_addr));\r
638                 //IP->MAC変換をテスト。\r
639                 if(eth_dest==NULL){\r
640                         return NyLPC_TBool_FALSE;\r
641                 }\r
642         }\r
643         //変換可能なら、イーサネットヘッダを更新して、送信処理へ。\r
644         tx_len=NyLPC_TEthernetIIHeader_setIPv4Tx(&(ethbuf->header),&(inst->_ref_config->eth_mac),eth_dest);\r
645         inst->_ethif->sendTxEthFrame(i_eth_buf,tx_len);\r
646         return NyLPC_TBool_TRUE;\r
647 }\r
648 \r
649 \r
650 \r
651 //static void startEther()\r
652 //{\r
653 //      NyLPC_TcUipService_t* inst=_NyLPC_TcUipService_inst;\r
654 //\r
655 //      //Ethernetの起動待ち\r
656 //      while(lEMACInit(_NyLPC_TcUipService_inst->_emac_semapho,&(inst->_ref_config->eth_mac))!= pdPASS )\r
657 //    {\r
658 //        vTaskDelay( 100 / portTICK_RATE_MS );\r
659 //    }\r
660 //      //Ethernetの割込み開始設定\r
661 //      portENTER_CRITICAL();\r
662 //      {\r
663 //              LPC_EMAC->IntEnable = ( INT_RX_DONE | INT_TX_DONE );\r
664 //              /* Set the interrupt priority to the max permissible to cause some\r
665 //              interrupt nesting. */\r
666 //              NVIC_SetPriority( ENET_IRQn, configEMAC_INTERRUPT_PRIORITY );\r
667 //\r
668 //              /* Enable the interrupt. */\r
669 //              NVIC_EnableIRQ( ENET_IRQn );\r
670 //      }\r
671 //      portEXIT_CRITICAL();\r
672 //}\r
673 //\r
674 //static void stopEther()\r
675 //{\r
676 //      portENTER_CRITICAL();\r
677 //      {\r
678 //              LPC_EMAC->IntEnable = (~(INT_RX_DONE|INT_TX_DONE))&LPC_EMAC->IntEnable;\r
679 //              NVIC_DisableIRQ( ENET_IRQn );\r
680 //      }\r
681 //      portEXIT_CRITICAL();\r
682 //}\r
683 \r