OSDN Git Service

add mbed.html
[mimic/MiMicSDK.git] / lib / src / uip / NyLPC_cIPv4Arp.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_cIPv4Arp.h"\r
56 #include "NyLPC_uip.h"\r
57 #include "NyLPC_cUipService_protected.h"\r
58 #include <string.h>\r
59 \r
60 \r
61 /**\r
62  * The maxium age of ARP table entries measured in 10ths of seconds.\r
63  *\r
64  * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD\r
65  * default).\r
66  */\r
67 #define UIP_ARP_MAXAGE 120\r
68 \r
69 \r
70 //static const struct NyLPC_TEthAddr broadcast_ethaddr = { { 0xff, 0xff, 0xff,0xff, 0xff, 0xff } };\r
71 //static const struct NyLPC_TIPv4Addr broadcast_ipaddr = { 0xfffffff };\r
72 \r
73 \r
74 \r
75 \r
76 static void uip_arp_update(NyLPC_TcIPv4Arp_t* i_inst,const struct NyLPC_TIPv4Addr* ipaddr,const struct NyLPC_TEthAddr *ethaddr);\r
77 /*-----------------------------------------------------------------------------------*/\r
78 /**\r
79  * Initialize the ARP module.\r
80  *\r
81  */\r
82 /*-----------------------------------------------------------------------------------*/\r
83 void NyLPC_cIPv4Arp_initialize(NyLPC_TcIPv4Arp_t* i_inst,const NyLPC_TcIPv4Config_t* i_ref_config)\r
84 {\r
85         int i;\r
86         struct NyLPC_TArpTableItem* tbl=i_inst->arp_table;\r
87         i_inst->_cfg = i_ref_config;\r
88         i_inst->arptime = 0;\r
89         i_inst->tmpage = 0;\r
90         for (i = 0; i < NyLPC_TcIPv4Arp_ARPTAB_SIZE; ++i) {\r
91                 memset(&(tbl[i].ipaddr), 0, sizeof(struct NyLPC_TIPv4Addr));\r
92         }\r
93 }\r
94 /*-----------------------------------------------------------------------------------*/\r
95 /**\r
96  * Periodic ARP processing function.\r
97  *\r
98  * This function performs periodic timer processing in the ARP module\r
99  * and should be called at regular intervals. The recommended interval\r
100  * is 10 seconds between the calls.\r
101  *\r
102  */\r
103 /*-----------------------------------------------------------------------------------*/\r
104 void NyLPC_cIPv4Arp_periodic(NyLPC_TcIPv4Arp_t* i_inst)\r
105 {\r
106         struct NyLPC_TArpTableItem* tbl=i_inst->arp_table;\r
107         struct NyLPC_TArpTableItem* tabptr;\r
108         int i;\r
109         i_inst->arptime++;\r
110         for (i = 0; i < NyLPC_TcIPv4Arp_ARPTAB_SIZE; ++i) {\r
111                 tabptr = &tbl[i];\r
112                 if (tabptr->ipaddr.v != 0 && i_inst->arptime - tabptr->time >= UIP_ARP_MAXAGE)\r
113                 {\r
114                         tabptr->ipaddr.v = 0;\r
115                 }\r
116         }\r
117 \r
118 }\r
119 /*-----------------------------------------------------------------------------------*/\r
120 /**\r
121  * ARP processing for incoming IP packets\r
122  *\r
123  * This function should be called by the device driver when an IP\r
124  * packet has been received. The function will check if the address is\r
125  * in the ARP cache, and if so the ARP cache entry will be\r
126  * refreshed. If no ARP cache entry was found, a new one is created.\r
127  *\r
128  * This function expects an IP packet with a prepended Ethernet header\r
129  * in the uip_buf[] buffer, and the length of the packet in the global\r
130  * variable uip_len.\r
131  */\r
132 /*-----------------------------------------------------------------------------------*/\r
133 void NyLPC_cIPv4Arp_incomingIp(NyLPC_TcIPv4Arp_t* i_inst,const struct NyLPC_TEthernetIIHeader* i_eth,struct NyLPC_TIPv4Addr i_ip_src)\r
134 {\r
135         //EtherとIPv4の値を読みだす。\r
136         /* Only insert/update an entry if the source IP address of the\r
137          incoming IP packet comes from a host on the local network. */\r
138         if ((i_ip_src.v & i_inst->_cfg->netmask.v) != (i_inst->_cfg->ip_addr.v & i_inst->_cfg->netmask.v)) {\r
139                 return;\r
140         }\r
141         uip_arp_update(i_inst,&(i_ip_src), &(i_eth->src));\r
142         return;\r
143 }\r
144 /**\r
145  * ARP processing for incoming ARP packets.\r
146  *\r
147  * This function should be called by the device driver when an ARP\r
148  * packet has been received. The function will act differently\r
149  * depending on the ARP packet type: if it is a reply for a request\r
150  * that we previously sent out, the ARP cache will be filled in with\r
151  * the values from the ARP reply. If the incoming ARP packet is an ARP\r
152  * request for our IP address, an ARP reply packet is created and put\r
153  * into the uip_buf[] buffer.\r
154  *\r
155  * When the function returns, the value of the global variable uip_len\r
156  * indicates whether the device driver should send out a packet or\r
157  * not. If uip_len is zero, no packet should be sent. If uip_len is\r
158  * non-zero, it contains the length of the outbound packet that is\r
159  * present in the uip_buf[] buffer.\r
160  *\r
161  * This function expects an ARP packet with a prepended Ethernet\r
162  * header in the uip_buf[] buffer, and the length of the packet in the\r
163  * global variable uip_len.\r
164  */\r
165 \r
166 \r
167 /**\r
168  * ARPパケットの読出し用構造体\r
169  */\r
170 struct TArpPacketPtr\r
171 {\r
172         struct NyLPC_TEthernetIIHeader header;\r
173         struct NyLPC_TArpHeader arp;\r
174 }PACK_STRUCT_END;\r
175 \r
176 /**\r
177  * arpパケットを処理します。\r
178  */\r
179 void* NyLPC_cIPv4Arp_rx(NyLPC_TcIPv4Arp_t* i_inst,const struct NyLPC_TArpHeader* i_arp, NyLPC_TUInt16 i_len, NyLPC_TUInt16* o_tx_len)\r
180 {\r
181         struct NyLPC_TArpHeader* arp_tx;\r
182         if (i_len < sizeof(struct NyLPC_TArpHeader)) {\r
183                 return NULL;\r
184         }\r
185         const NyLPC_TcIPv4Config_t* cfg=i_inst->_cfg;\r
186         switch (i_arp->opcode) {\r
187         case NyLPC_HTONS(ARP_REQUEST):\r
188                 /* ARP request. If it asked for our address, we send out a reply. */\r
189                 if (NyLPC_TIPv4Addr_isEqual(&(i_arp->dipaddr), &(cfg->ip_addr))) {\r
190                         /* First, we register the one who made the request in our ARP\r
191                          table, since it is likely that we will do more communication\r
192                          with this host in the future. */\r
193                         uip_arp_update(i_inst,&(i_arp->sipaddr), &i_arp->shwaddr);\r
194                         //イーサネットヘッダもいじくるから\r
195                         arp_tx=(struct NyLPC_TArpHeader*)NyLPC_cUipService_allocSysTxBuf();\r
196 \r
197                         /* The reply opcode is 2. */\r
198                         arp_tx->hwtype          =i_arp->hwtype;\r
199                         arp_tx->protocol        =i_arp->protocol;\r
200                         arp_tx->hwlen           =i_arp->hwlen;\r
201                         arp_tx->protolen        =i_arp->protolen;\r
202                         arp_tx->opcode = NyLPC_HTONS(2);\r
203                         memcpy(arp_tx->dhwaddr.addr, i_arp->shwaddr.addr, 6);\r
204                         memcpy(arp_tx->shwaddr.addr, cfg->eth_mac.addr, 6);\r
205                         arp_tx->dipaddr = i_arp->sipaddr;\r
206                         arp_tx->sipaddr = cfg->ip_addr;\r
207                         *o_tx_len=NyLPC_TEthernetIIHeader_setArpTx((((struct NyLPC_TEthernetIIHeader*)arp_tx)-1),&(i_inst->_cfg->eth_mac));\r
208 \r
209 //                      /* The reply opcode is 2. */\r
210 //                      i_arp->opcode = NyLPC_HTONS(2);\r
211 //\r
212 //                      memcpy(i_arp->dhwaddr.addr, i_arp->shwaddr.addr, 6);\r
213 //                      memcpy(i_arp->shwaddr.addr, cfg->eth_mac.addr, 6);\r
214 //\r
215 //                      i_arp->dipaddr = i_arp->sipaddr;\r
216 //                      i_arp->sipaddr = cfg->ip_addr;\r
217                         return arp_tx;\r
218                 }\r
219                 break;\r
220         case NyLPC_HTONS(ARP_REPLY):\r
221                 // ARP reply. We insert or update the ARP table if it was meant for us.\r
222                 if (NyLPC_TIPv4Addr_isEqual(&(i_arp->dipaddr),&(cfg->ip_addr))) {\r
223                         uip_arp_update(i_inst,&(i_arp->sipaddr), &i_arp->shwaddr);\r
224                 }\r
225                 break;\r
226         }\r
227         return NULL;\r
228 }\r
229 /**\r
230  * Prepend Ethernet header to an outbound IP packet and see if we need\r
231  * to send out an ARP request.\r
232  *\r
233  * This function should be called before sending out an IP packet. The\r
234  * function checks the destination IP address of the IP packet to see\r
235  * what Ethernet MAC address that should be used as a destination MAC\r
236  * address on the Ethernet.\r
237  *\r
238  * If the destination IP address is in the local network (determined\r
239  * by logical ANDing of netmask and our IP address), the function\r
240  * checks the ARP cache to see if an entry for the destination IP\r
241  * address is found. If so, an Ethernet header is prepended and the\r
242  * function returns. If no ARP cache entry is found for the\r
243  * destination IP address, the packet in the uip_buf[] is replaced by\r
244  * an ARP request packet for the IP address. The IP packet is dropped\r
245  * and it is assumed that they higher level protocols (e.g., TCP)\r
246  * eventually will retransmit the dropped packet.\r
247  *\r
248  * If the destination IP address is not on the local network, the IP\r
249  * address of the default router is used instead.\r
250  *\r
251  * When the function returns, a packet is present in the uip_buf[]\r
252  * buffer, and the length of the packet is in the global variable\r
253  * uip_len.\r
254  */\r
255 \r
256 /**\r
257  * IPアドレス-MACアドレス交換\r
258  */\r
259 const struct NyLPC_TEthAddr* NyLPC_cIPv4Arp_IPv4toEthAddr(NyLPC_TcIPv4Arp_t* i_inst,const struct NyLPC_TIPv4Addr i_ip_addr)\r
260 {\r
261         int i;\r
262         struct NyLPC_TArpTableItem *tabptr;\r
263         //ARPテーブルから検索\r
264         for (i = NyLPC_TcIPv4Arp_ARPTAB_SIZE - 1; i >= 0; i--) {\r
265                 tabptr = &i_inst->arp_table[i];\r
266                 if (NyLPC_TIPv4Addr_isEqual(&i_ip_addr,&(tabptr->ipaddr))) {\r
267                         return &tabptr->ethaddr;\r
268                 }\r
269         }\r
270         return NULL;\r
271 }\r
272 \r
273 \r
274 \r
275 \r
276 \r
277 \r
278 \r
279 static void uip_arp_update(NyLPC_TcIPv4Arp_t* i_inst,const struct NyLPC_TIPv4Addr* ipaddr,const struct NyLPC_TEthAddr *ethaddr)\r
280 {\r
281         register struct NyLPC_TArpTableItem *tabptr;\r
282         int i,c;\r
283         /* Walk through the ARP mapping table and try to find an entry to\r
284          update. If none is found, the IP -> MAC address mapping is\r
285          inserted in the ARP table. */\r
286         for (i = 0; i < NyLPC_TcIPv4Arp_ARPTAB_SIZE; ++i) {\r
287                 tabptr = &i_inst->arp_table[i];\r
288                 /* Only check those entries that are actually in use. */\r
289                 if (tabptr->ipaddr.v != 0) {\r
290                         /* Check if the source IP address of the incoming packet matches\r
291                          the IP address in this ARP table entry. */\r
292                         if (ipaddr->v == tabptr->ipaddr.v) {\r
293                                 /* An old entry found, update this and return. */\r
294                                 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);\r
295                                 tabptr->time = i_inst->arptime;\r
296 \r
297                                 return;\r
298                         }\r
299                 }\r
300         }\r
301 \r
302         /* If we get here, no existing ARP table entry was found, so we\r
303          create one. */\r
304         /* First, we try to find an unused entry in the ARP table. */\r
305         for (i = 0; i < NyLPC_TcIPv4Arp_ARPTAB_SIZE; ++i) {\r
306                 tabptr = &i_inst->arp_table[i];\r
307                 if (tabptr->ipaddr.v == 0) {\r
308                         break;\r
309                 }\r
310         }\r
311 \r
312         /* If no unused entry is found, we try to find the oldest entry and\r
313          throw it away. */\r
314         if (i == NyLPC_TcIPv4Arp_ARPTAB_SIZE) {\r
315                 i_inst->tmpage = 0;\r
316                 c = 0;\r
317                 for (i = 0; i < NyLPC_TcIPv4Arp_ARPTAB_SIZE; ++i) {\r
318                         tabptr = &i_inst->arp_table[i];\r
319                         if (i_inst->arptime - tabptr->time > i_inst->tmpage) {\r
320                                 i_inst->tmpage = i_inst->arptime - tabptr->time;\r
321                                 c = i;\r
322                         }\r
323                 }\r
324                 i = c;\r
325                 tabptr = &i_inst->arp_table[i];\r
326         }\r
327 \r
328         /* Now, i is the ARP table entry which we will fill with the new information. */\r
329         tabptr->ipaddr = *ipaddr;\r
330         memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);\r
331         tabptr->time = i_inst->arptime;\r
332 }\r
333 \r
334 \r