Aktuální adresář: FITkit /
trunk /
mcu /
libs /
enc28j60 /
enc28j60_ip.c
1 /*******************************************************************************
2 enc28j60_ip.c: Sitova vrstva modelu TCP/IP
3 Copyright (C) 2010 Brno University of Technology,
4 Faculty of Information Technology
5 Author(s): Martin Musil <xmusil34 AT fit.vutbr.cz>
6
7 LICENSE TERMS
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in
16 the documentation and/or other materials provided with the
17 distribution.
18 3. All advertising materials mentioning features or use of this software
19 or firmware must display the following acknowledgement:
20
21 This product includes software developed by the University of
22 Technology, Faculty of Information Technology, Brno and its
23 contributors.
24
25 4. Neither the name of the Company nor the names of its contributors
26 may be used to endorse or promote products derived from this
27 software without specific prior written permission.
28
29 This software or firmware is provided ``as is'', and any express or implied
30 warranties, including, but not limited to, the implied warranties of
31 merchantability and fitness for a particular purpose are disclaimed.
32 In no event shall the company or contributors be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability, whether
37 in contract, strict liability, or tort (including negligence or
38 otherwise) arising in any way out of the use of this software, even
39 if advised of the possibility of such damage.
40
41 $Id$
42
43 *******************************************************************************/
44
45 #include "enc28j60_spi.h"
46 #include "enc28j60_eth.h"
47 #include "enc28j60_arp.h"
48 #include "enc28j60_ip.h"
49 #include "enc28j60_icmp.h"
50 #include "enc28j60_tcp.h"
51 #include "enc28j60_udp.h"
52
53 // pro prevod 4xchar na 1 long, pro IP adresy, v "net order"
54 #define CHAR_TO_LONG(x0,x1,x2,x3) ( ((unsigned long)x0<<24)|((unsigned long)x1<<16)|((unsigned int)x2<<8)|x3)
55
56
57 extern unsigned char broadcast_mac[MAC_LEN];
58
59 unsigned long local_ip = 0;
60 unsigned long ip_netmask = 0;
61 unsigned long default_gateway = 0;
62 unsigned long dns_server = 0;
63 unsigned int ip_seq_num = 1;
64
65
66 /**
67
68 **/
69 void ip_recv(void){
70
71 struct ip_h ip_header;
72
73 if(rx_read(&ip_header,IP_HEADER_LEN) != IP_HEADER_LEN)
74 return;
75
76 //kontrola verze IP a minimalni delky hlavicky
77 if((ip_header.ipv != IPv4) | (ip_header.header_len < 4))
78 return;
79
80 //kontrola fragmentacnich flagu
81 if(ip_header.fragment & NTOHS(IP_FRAG_OFFSET|IP_FRAG_MORE)) //fragmentovany paket,zahodit
82 return;
83
84 //kontrola IP adresy
85 if(NTOHL(ip_header.dest_ip) != local_ip && (NTOHL(ip_header.dest_ip)|ip_netmask) != IP_BROADCAST )
86 return;
87
88
89 //pokud je hlavicka delsi nez obvyklych 20B (volitelne polozky), zahodime je
90 if( ( ((unsigned char)ip_header.header_len) <<2) > IP_HEADER_LEN){ //header_len *4
91 rx_skip ( ( ((unsigned char)ip_header.header_len) <<2) - IP_HEADER_LEN);
92 }
93
94 //odstraneni paddingu
95 if(NTOHS(ip_header.length) < MIN_IP_LEN){
96 rx_cut_padding(MIN_IP_LEN - NTOHS(ip_header.length));
97
98 }
99
100
101 switch(ip_header.protocol){
102 case IP_PROTO_ICMP:
103 icmp_recv(&ip_header);
104 break;
105 case IP_PROTO_TCP:
106 tcp_recv(&ip_header);
107 break;
108 case IP_PROTO_UDP:
109 udp_recv(&ip_header);
110 break;
111 }
112
113 return;
114 }
115
116 /**
117
118 **/
119 char ip_send(unsigned long dest_addr,unsigned char protocol){
120
121 struct ip_h ip_header;
122
123 tx_seek(IP_HEADER); //jiz zde kvuli volani tx_data_len() nize
124
125 ip_header.ipv = IPv4;
126 ip_header.header_len = IP_HEADER_LEN >> 2; // deleno ctyrmi, udava se totiz v DWORD
127 ip_header.tos = 0;
128 ip_header.length = HTONS(tx_data_len());
129 ip_header.identification = HTONS(ip_seq_num);
130 ip_seq_num++;
131
132 ip_header.fragment = 0;
133 ip_header.ttl = DEFAULT_TTL;
134 ip_header.protocol = protocol;
135 ip_header.checksum = 0;
136 ip_header.src_ip = HTONL(local_ip);
137 ip_header.dest_ip = HTONL(dest_addr);
138
139 //pri pocitani checksumu z hlavicky, ktera je big endian, jiz nemusime checksum prevadet pomoci HTONS
140 ip_header.checksum = count_checksum(&ip_header,IP_HEADER_LEN);
141
142
143 tx_write(&ip_header,IP_HEADER_LEN);
144
145
146 //*****************************
147 //cil nelezi ve stejne podsiti
148 //*****************************
149 if(default_gateway != 0){
150 if((local_ip & ip_netmask) != (dest_addr & ip_netmask)){
151 dest_addr = default_gateway;
152 }
153 }
154
155 //********
156 //ARP
157 //*********
158 char * dest_mac;
159
160 if(dest_addr == IP_BROADCAST){ //IP broadcast se posila na broadcastovou mac
161 dest_mac = broadcast_mac;
162 }
163 else{
164 dest_mac = arp_table_find(dest_addr);
165 }
166
167 if(dest_mac == NULL){ //neexistuje arp zaznam
168
169 //ulozeni ukazatelu do bufferu behem vyrizovani ARP dotazu
170 unsigned char last_act = tx_act();
171
172 tx_save(last_act);
173
174 //odeslani ARP dotazu
175 arp_send(dest_addr);
176
177 unsigned int timer = ARP_TIMEOUT; //timeout
178
179 //cekani na ARP odpoved
180 while((arp_table_find(dest_addr) == NULL) & (timer-- > 0) ){ //az dojde odpoved, zapise se do arp tabulky
181 ENC28J60_idle(); //obsluha prichozich paketu
182 };
183
184 dest_mac = arp_table_find(dest_addr);
185
186 if( dest_mac == NULL){ //odpoved na arp nedosla do timeoutu
187 if(last_act == TX1)
188 tx_unlock(TX1); //vypnuti ochrany proti prepsani tx bufferu
189 else if(last_act == TX2)
190 tx_unlock(TX2);
191
192
193 return -2;
194 }
195 else{
196 tx_load(last_act);
197 return eth_send(dest_mac,ETH_PROTO_IP); //odeslani paketu na ziskanou mac adresu
198 }
199
200 }
201
202 return eth_send(dest_mac,ETH_PROTO_IP);
203 }
204
205
206 /**
207
208 **/
209 unsigned int count_checksum(void* pointer,int count){ //vypocet CRC souctu,podle RFC 1071
210
211 unsigned long sum = 0;
212 unsigned int* ptr = (unsigned int*)pointer;
213
214 while( count > 1 ){
215 sum += *(ptr++);
216 count -=2;
217 }
218
219 if(count == 1)
220 sum += *((unsigned char*) ptr);
221
222 while(sum >> 16){
223 sum = (sum & 0xFFFF) + (sum >> 16);
224 }
225
226 return (unsigned int) ~sum;
227 }
228
229
230
231 /**
232
233 **/
234 inline void set_ip(unsigned char a0,unsigned char a1,unsigned char a2, unsigned char a3){
235 local_ip = CHAR_TO_LONG(a0,a1,a2,a3);
236 }
237
238 /**
239
240 **/
241 inline void set_ip_l(unsigned long ip){
242 local_ip = ip;
243 }
244 /**
245
246 **/
247 inline unsigned long get_ip(){
248 return local_ip;
249 }
250
251 /**
252
253 **/
254 inline void set_netmask(unsigned char m0,unsigned char m1,unsigned char m2, unsigned char m3){
255 ip_netmask = CHAR_TO_LONG(m0,m1,m2,m3);
256 }
257 /**
258
259 **/
260 inline void set_netmask_l(unsigned long netmask){
261 ip_netmask = netmask;
262 }
263 /**
264
265 **/
266 inline unsigned long get_netmask(){
267 return ip_netmask;
268 }
269
270 /**
271
272 **/
273 inline void set_gateway(unsigned char g0,unsigned char g1,unsigned char g2, unsigned char g3){
274 default_gateway = CHAR_TO_LONG(g0,g1,g2,g3);
275 }
276 /**
277
278 **/
279 inline void set_gateway_l(unsigned long gateway){
280 default_gateway = gateway;
281 }
282 /**
283
284 **/
285 inline unsigned long get_gateway(){
286 return default_gateway;
287 }
288
289 /**
290
291 **/
292 inline void set_dns_server(unsigned char d0,unsigned char d1,unsigned char d2, unsigned char d3){
293 dns_server = CHAR_TO_LONG(d0,d1,d2,d3);
294 }
295 /**
296
297 **/
298 inline void set_dns_server_l(unsigned long dns){
299 dns_server = dns;
300 }
301 /**
302
303 **/
304 inline unsigned long get_dns_server(){
305 return dns_server;
306 }
307
308