OSDN Git Service

8663d76028e46cffd500dfd9fa1d13ab8d4d144b
[mimic/MiMicSDK.git] / lib / src / uip / NyLPC_uip.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_uip.h"\r
56 \r
57 \r
58 \r
59 const struct NyLPC_TIPv4Addr NyLPC_TIPv4Addr_ZERO={0x00000000};\r
60 const struct NyLPC_TIPv4Addr NyLPC_TIPv4Addr_ALL ={0xffffffff};\r
61 const struct NyLPC_TIPv4Addr NyLPC_TIPv4Addr_BROADCAST = { 0xffffffff };\r
62 const struct NyLPC_TIPv4Addr NyLPC_TIPv4Addr_MULTICAST = NyLPC_TIPv4Addr_pack(224,0,0,0);\r
63 const struct NyLPC_TIPv4Addr NyLPC_TIPv4Addr_MULTICAST_MASK = NyLPC_TIPv4Addr_pack(224,0,0,0);\r
64 const struct NyLPC_TIPv4Addr NyLPC_TIPv4Addr_APIPA_MASK = NyLPC_TIPv4Addr_pack(255,255,0,0);\r
65 \r
66 NyLPC_TInt16 NyLPC_TIPv4Addr_toString(const struct NyLPC_TIPv4Addr* i_ip,NyLPC_TChar* i_buf)\r
67 {\r
68         NyLPC_TUInt32 ip;\r
69         NyLPC_TChar* p=i_buf;\r
70         NyLPC_TUInt8 v;\r
71         NyLPC_TInt8 l;\r
72         //IPをホストオーダーにする。\r
73         ip=NyLPC_NTOHL(i_ip->v);\r
74         for(l=3;l>=0;l--){\r
75                 v=(ip>>(8*l))&0xff;\r
76                 if(v>100){\r
77                         *p=(v/100)+'0';\r
78                         v=v%100;\r
79                         p++;\r
80                 }\r
81                 if(v>10){\r
82                         *p=(v/10)+'0';\r
83                         v=v%10;\r
84                         p++;\r
85                 }\r
86                 *p=v+'0';\r
87                 *(p+1)='.';\r
88                 p+=2;\r
89         }\r
90         *(p-1)='\0';\r
91         return p-i_buf-1;\r
92 }\r
93 \r
94 \r
95 NyLPC_TUInt16 NyLPC_uip_chksum(NyLPC_TUInt16 sum, const NyLPC_TUInt8 *data, NyLPC_TUInt16 len)\r
96 {\r
97         NyLPC_TUInt16 t;\r
98         const NyLPC_TUInt8 *dataptr;\r
99         const NyLPC_TUInt8 *last_byte;\r
100 \r
101         dataptr = data;\r
102         last_byte = data + len - 1;\r
103 \r
104         while (dataptr < last_byte) { /* At least two more bytes */\r
105                 t = (dataptr[0] << 8) + dataptr[1];\r
106                 sum += t;\r
107                 if (sum < t) {\r
108                         sum++; /* carry */\r
109                 }\r
110                 dataptr += 2;\r
111         }\r
112 \r
113         if (dataptr == last_byte) {\r
114                 t = (dataptr[0] << 8) + 0;\r
115                 sum += t;\r
116                 if (sum < t) {\r
117                         sum++; /* carry */\r
118                 }\r
119         }\r
120 \r
121         /* Return sum in host byte order. */\r
122         return sum;\r
123 }\r
124 \r
125 /*--------------------------------------------------------------------------------\r
126  *\r
127  * struct NyLPC_TEthernetIIHeader\r
128  *\r
129  *------------------------------------------------------------------------------*/\r
130 \r
131 /**\r
132  * Ethernetヘッダの内容を、ARPパケットの内容に一致するように書き換えます。\r
133  * i_structの後方にあるものと仮定します。\r
134  * 戻り値は、フレームの長さです。\r
135  */\r
136 NyLPC_TUInt16 NyLPC_TEthernetIIHeader_setArpTx(\r
137         struct NyLPC_TEthernetIIHeader* i_struct,\r
138         const struct NyLPC_TEthAddr* i_my_eth_addr)\r
139 {\r
140         struct NyLPC_TArpHeader* arph=(struct NyLPC_TArpHeader*)(((NyLPC_TUInt8*)i_struct)+sizeof(struct NyLPC_TEthernetIIHeader));\r
141 \r
142         i_struct->type = NyLPC_HTONS(NyLPC_TEthernetIIHeader_TYPE_ARP);\r
143         switch(arph->opcode){\r
144         case NyLPC_HTONS(ARP_REPLY):\r
145                 memcpy(i_struct->src.addr, i_my_eth_addr->addr, 6);\r
146                 memcpy(i_struct->dest.addr, arph->dhwaddr.addr, 6);\r
147                 break;\r
148         case NyLPC_HTONS(ARP_REQUEST):\r
149                 memset(i_struct->dest.addr, 0xff, 6);\r
150                 memcpy(i_struct->src.addr, i_my_eth_addr->addr, 6);\r
151                 break;\r
152         }\r
153         return sizeof(struct NyLPC_TEthernetIIHeader)+sizeof(struct NyLPC_TArpHeader);\r
154 }\r
155 \r
156 /**\r
157  * イーサネットヘッダをIPv4向けにセットアップする。\r
158  * 関数は、ペイロードをIPv4ヘッダとして、フレームサイズを計算する。\r
159  */\r
160 NyLPC_TUInt16 NyLPC_TEthernetIIHeader_setIPv4Tx(\r
161         struct NyLPC_TEthernetIIHeader* i_eth,\r
162         const struct NyLPC_TEthAddr* i_src_eth_addr,\r
163         const struct NyLPC_TEthAddr* i_dest_eth_addr)\r
164 {\r
165         struct NyLPC_TIPv4Header* iph=(struct NyLPC_TIPv4Header*)(((NyLPC_TUInt8*)i_eth)+sizeof(struct NyLPC_TEthernetIIHeader));\r
166 \r
167         i_eth->type = NyLPC_HTONS(NyLPC_TEthernetIIHeader_TYPE_IP);\r
168         /* Build an ethernet header. */\r
169         memcpy(i_eth->dest.addr,i_dest_eth_addr, 6);\r
170         memcpy(i_eth->src.addr, i_src_eth_addr->addr, 6);\r
171 \r
172 \r
173         //IPフラグメントに応じたサイズ計算\r
174         switch(iph->proto){\r
175         case UIP_PROTO_TCP:\r
176                 return sizeof(struct NyLPC_TEthernetIIHeader)+NyLPC_htons(iph->len16);\r
177         case UIP_PROTO_UDP:\r
178                 return sizeof(struct NyLPC_TEthernetIIHeader)+NyLPC_htons(iph->len16);\r
179         case UIP_PROTO_ICMP:\r
180                 return sizeof(struct NyLPC_TEthernetIIHeader)+NyLPC_htons(iph->len16);\r
181         }\r
182         return 0;\r
183 }\r
184 /*--------------------------------------------------------------------------------\r
185  *\r
186  * struct NyLPC_TIPv4Header\r
187  *\r
188  *------------------------------------------------------------------------------*/\r
189 \r
190 /**\r
191  * based on uip_ipchksum\r
192  */\r
193 NyLPC_TUInt16 NyLPC_TIPv4Header_makeIpChecksum(const struct NyLPC_TIPv4Header* ip_header)\r
194 {\r
195         NyLPC_TUInt16 sum;\r
196         sum = NyLPC_uip_chksum(0, (const NyLPC_TUInt8 *)ip_header,NyLPC_TIPv4Header_getHeaderLength(ip_header));\r
197         return (sum == 0) ? 0xffff : NyLPC_htons(sum);\r
198 }\r
199 \r
200 \r
201 \r
202 NyLPC_TBool NyLPC_TIPv4Header_isCorrectIpCheckSum(const struct NyLPC_TIPv4Header* ip_header)\r
203 {\r
204         return (NyLPC_TIPv4Header_makeIpChecksum(ip_header)==0xffff);\r
205 }\r
206 \r
207 NyLPC_TBool NyLPC_cIPv4Packet_isCorrectTcpCheckSum(const struct NyLPC_TIPv4Header* ip_header)\r
208 {\r
209         return (NyLPC_TIPv4Header_makeTcpChecksum(ip_header) == 0xffff);\r
210 }\r
211 \r
212 \r
213 \r
214 \r
215 /**\r
216  * TCPチェックサムを計算します。\r
217  * ペイロードはIPヘッダの後方に連続して存在する物と仮定します。\r
218  * i_lenは、ペイロード長さ
219  */\r
220 NyLPC_TUInt16 NyLPC_TIPv4Header_makeTcpChecksum(\r
221         const struct NyLPC_TIPv4Header* i_iph)\r
222 {\r
223         NyLPC_TUInt16 sum;\r
224         NyLPC_TUInt16 iph_len=NyLPC_TIPv4Header_getHeaderLength(i_iph);\r
225         NyLPC_TUInt16 len = NyLPC_ntohs((i_iph)->len16)- iph_len;\r
226         NyLPC_ArgAssert(i_iph!=NULL);\r
227         /*TCP疑似ヘッダ部分*/\r
228         /* IP protocol and length fields. This addition cannot carry. */\r
229         sum = len + i_iph->proto;\r
230         /* Sum IP source and destination addresses. */\r
231         sum = NyLPC_uip_chksum(sum, (NyLPC_TUInt8 *) &(i_iph->srcipaddr), 2 * sizeof(struct NyLPC_TIPv4Addr));\r
232         /* Sum TCP header and data. */\r
233         sum = NyLPC_uip_chksum(sum, (((NyLPC_TUInt8 *)(i_iph))+iph_len),len);\r
234         //      sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], i_len_of_data);\r
235         return (sum == 0) ? 0xffff : NyLPC_htons(sum);\r
236 }\r
237 \r
238 static  NyLPC_TUInt16 pid=0x3939;\r
239 /**\r
240  * IPヘッダを送信パケット用に設定する。\r
241  * ipid16にはコールされるたびに新しい値を設定する。\r
242  * ipcecksumには0を設定する。\r
243  * この関数は、パケットサイズ,ローカルIP/リモートIPの設定はしない。\r
244  */\r
245 void NyLPC_TIPv4Header_writeTxIpHeader(\r
246         struct NyLPC_TIPv4Header* i_struct,\r
247         NyLPC_TUInt8 i_proto)\r
248 {\r
249         //IPパケットのセット\r
250         i_struct->proto=i_proto;\r
251         i_struct->ttl = UIP_DEFAULT_IP_TTL;\r
252         i_struct->tos = 0;\r
253         i_struct->ipid16=(pid++);\r
254         i_struct->ipoffset=0;//NyLPC_HTONS(0|0x4000);\r
255         i_struct->ipchksum = 0;\r
256 }\r
257 /*--------------------------------------------------------------------------------\r
258  *\r
259  * struct NyLPC_TIPv6Header\r
260  *\r
261  *------------------------------------------------------------------------------*/\r
262 #define IPV6_HEADER_SIZE 40\r
263 /**\r
264  * IPヘッダーを作って埋める関数\r
265  */\r
266 void NyLPC_TIPv6Header_setSendHeader(\r
267         struct NyLPC_TIPv6Header* i_iph,\r
268         uip_ip6addr_t i_src,\r
269         uip_ip6addr_t i_dest,\r
270         NyLPC_TUInt8 i_proto,\r
271         NyLPC_TUInt8 i_ttl,\r
272         NyLPC_TUInt16 i_len)\r
273 {\r
274         i_iph->srcipaddr=i_src;\r
275         i_iph->destipaddr=i_dest;\r
276         i_iph->proto=i_proto;\r
277         i_iph->ttl = i_ttl;\r
278         i_iph->vtc = 0x60;\r
279         i_iph->tcflow = 0x00;\r
280         i_iph->flow = 0x00;\r
281         i_iph->len16= NyLPC_htons(i_len - IPV6_HEADER_SIZE);\r
282         return;\r
283 }\r
284 \r
285 \r
286 /**\r
287  * チェックサムは、TCP疑似ヘッダから計算。\r
288  * i_tcpiphの送信/受信アドレス、ProtocolID,DATAフィールドは有効であること。\r
289  */\r
290 NyLPC_TUInt16 NyLPC_TIPv6Header_makeTcpChecksum(\r
291         struct NyLPC_TIPv6Header* i_iph,\r
292         NyLPC_TUInt16 i_len)\r
293 {\r
294         NyLPC_TUInt16 sum;\r
295         NyLPC_TUInt16 len;\r
296         len = i_len;\r
297         /*TCP疑似ヘッダ部分*/\r
298         /* IP protocol and length fields. This addition cannot carry. */\r
299         sum = len + i_iph->proto;\r
300         /* Sum IP source and destination addresses. */\r
301         sum = NyLPC_uip_chksum(sum, (NyLPC_TUInt8 *) &(i_iph->srcipaddr), 2 * sizeof(uip_ip6addr_t));\r
302         /* Sum TCP header and data. */\r
303         sum = NyLPC_uip_chksum(sum, (((NyLPC_TUInt8 *)(i_iph))+IPV6_HEADER_SIZE),len);\r
304         //      sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], i_len_of_data);\r
305         return (sum == 0) ? 0xffff : NyLPC_htons(sum);\r
306 }\r
307 \r
308 \r
309 \r
310 /*--------------------------------------------------------------------------------\r
311  *\r
312  * struct NyLPC_TTcpHeader\r
313  *\r
314  *------------------------------------------------------------------------------*/\r
315 \r
316 \r
317 /**\r
318  * MMSオプションの値を返す。
319  */\r
320 NyLPC_TBool NyLPC_TTcpHeader_getTcpMmsOpt(\r
321         const struct NyLPC_TTcpHeader* i_struct,NyLPC_TUInt16* o_val)\r
322 {\r
323         NyLPC_TUInt8* opt;\r
324         opt=NyLPC_TTcpHeader_getTcpOptFragmentPtr(i_struct,TCP_OPT_MSS);\r
325         if(opt!=NULL){\r
326                 if (*(opt+1) == TCP_OPT_MSS_LEN)\r
327                 {\r
328                         // An MSS option with the right option length.\r
329                         *o_val = ((NyLPC_TUInt16) (*(opt+2)) << 8) | (NyLPC_TUInt16) (*(opt + 3));\r
330                         //And we are done processing options.\r
331                         return NyLPC_TBool_TRUE;\r
332                 }\r
333         }\r
334         return NyLPC_TBool_FALSE;\r
335 }\r
336 \r
337 #define DEFAULT_TCP_HEADER_LEN 20\r
338 /**\r
339  * TCPフラグメントのポインタを返す。\r
340  */\r
341 NyLPC_TUInt8* NyLPC_TTcpHeader_getTcpOptFragmentPtr(\r
342         const struct NyLPC_TTcpHeader* i_struct,\r
343         NyLPC_TUInt8 i_opt_id)\r
344 {\r
345         NyLPC_TUInt8 opt;\r
346         int c;\r
347         NyLPC_TUInt8* opt_buf=((NyLPC_TUInt8*)(i_struct+1));\r
348 \r
349         /* Parse the TCP MSS option, if present. */\r
350         if ((i_struct->tcpoffset & 0xf0) > 0x50){\r
351                 for (c = 0; c < ((i_struct->tcpoffset >> 4) - 5) << 2;)\r
352                 {\r
353                         opt=opt_buf[c];\r
354                         if(opt==i_opt_id){\r
355                                 return opt_buf+c;//found!\r
356                         }\r
357                         switch(opt)\r
358                         {\r
359                         case TCP_OPT_NOOP:\r
360                                 continue;//NOP option.\r
361                         case TCP_OPT_END:\r
362                                 return NULL;//End of options.\r
363                         default:\r
364                                 // All other options have a length field, so that we easily can skip past them.\r
365                                 if (opt_buf[1 + c] == 0) {\r
366                                         // If the length field is zero, the options are malformed and we don't process them further.\r
367                                         NyLPC_OnErrorGoto(ERROR_INVALID_OPTION);\r
368                                 }\r
369                                 c += opt_buf[1 + c];\r
370                         }\r
371                 }\r
372         }\r
373 ERROR_INVALID_OPTION:\r
374         return NULL;\r
375 }\r
376 /*\r
377  * Optionパラメタを書きだす。\r
378  */\r
379 void NyLPC_TTcpHeader_setMmsOpt(NyLPC_TUInt8* i_opt_addr,NyLPC_TUInt16 i_mms)\r
380 {\r
381         i_opt_addr[0] = TCP_OPT_MSS;\r
382         i_opt_addr[1] = TCP_OPT_MSS_LEN;\r
383         i_opt_addr[2] = (i_mms) / 256;\r
384         i_opt_addr[3] = (i_mms) & 255;\r
385         return;\r
386 }\r
387 \r
388 \r
389 NyLPC_TUInt16 NyLPC_TTcpHeader_getHeaderLength(const struct NyLPC_TTcpHeader* ip_header)\r
390 {\r
391         return (ip_header->tcpoffset>>4)*4;\r
392 }\r
393 /*--------------------------------------------------------------------------------\r
394  *\r
395  * struct NyLPC_TUdpHeader\r
396  *\r
397  *------------------------------------------------------------------------------*/\r
398 \r
399 \r
400 \r
401 /*--------------------------------------------------------------------------------\r
402  *\r
403  * struct NyLPC_TArpHeader\r
404  *\r
405  *------------------------------------------------------------------------------*/\r
406 /**\r
407  * i_req_addrを問い合わせるARP_REQUESTを生成します。\r
408  */\r
409 void NyLPC_TArpHeader_setArpRequest(\r
410         struct NyLPC_TArpHeader* i_struct,\r
411         const struct NyLPC_TIPv4Addr i_saddr,\r
412         const struct NyLPC_TEthAddr* i_srceth,\r
413         const struct NyLPC_TIPv4Addr* i_req_addr)\r
414 {\r
415         memset(i_struct->dhwaddr.addr, 0x00, 6);\r
416         memcpy(i_struct->shwaddr.addr, i_srceth, 6);\r
417         i_struct->dipaddr=*i_req_addr;\r
418         i_struct->sipaddr=i_saddr;\r
419         i_struct->opcode = NyLPC_HTONS(ARP_REQUEST); /* ARP request. */\r
420         i_struct->hwtype = NyLPC_HTONS(ARP_HWTYPE_ETH);\r
421         i_struct->protocol = NyLPC_HTONS(NyLPC_TEthernetIIHeader_TYPE_IP);\r
422         i_struct->hwlen = 6;\r
423         i_struct->protolen = 4;\r
424         return;\r
425 }\r
426 \r
427 /*--------------------------------------------------------------------------------\r
428  *\r
429  * class IPv4Route\r
430  *\r
431  *------------------------------------------------------------------------------*/\r
432 \r
433 \r