c2b040193a777c09bdc595c95492b57a2521db87
Stefan Schuermans added file headers

Stefan Schuermans authored 12 years ago

1) /* MIPS I system
2)  * Copyright 2011-2012 Stefan Schuermans <stefan@schuermans.info>
3)  * Copyleft GNU public license V2 or later
4)  *          http://www.gnu.org/copyleft/gpl.html
5)  */
6) 
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

7) #include "arp.h"
8) #include "checksum.h"
9) #include "config.h"
10) #include "ethernet.h"
11) #include "icmp.h"
12) #include "ip.h"
13) #include "macros.h"
14) #include "memcpy.h"
15) #include "nethelp.h"
16) #include "udp.h"
17) 
18) // timing parameters
19) #define IP_BUFFER_TICKS_MAX 50 // maximum age of buffered IP packet (in 200ms)
20) 
21) /**
22)  * buffers for IP packets to transmit
23)  *  - used if MAC is unknown when packet shall be transmitted
24)  *  - packet is sent when MAC becomes known
25)  *  - some buffers with different length (packets have different lengths)
26)  */
27) //@{
28) unsigned int ip_buffer0[20];
29) unsigned int ip_buffer1[20];
30) unsigned int ip_buffer2[40];
31) unsigned int ip_buffer3[80];
32) //@}
33) /// table with buffers
34) struct ip_buffer_table
35) {
36)   void *ptr; ///< pointer to buffer for packet
37)   unsigned int buf_sz; ///< size of buffer
38)   unsigned int pkg_sz; ///< size of packet in buffer, 0 for packet
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

39)   unsigned int ticks; ///< age of entry (in 200ms)
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

40) } ip_buffer_tab[] =
41) { // put smaller buffers in front of larger buffers
42)   //  - then short packets will use smaller buffers more often
43)   { ip_buffer0, sizeof(ip_buffer0), 0, 0 },
44)   { ip_buffer1, sizeof(ip_buffer1), 0, 0 },
45)   { ip_buffer2, sizeof(ip_buffer2), 0, 0 },
46)   { ip_buffer3, sizeof(ip_buffer3), 0, 0 },
47) };
48) 
49) /// initialize
50) void ip_init(void)
51) {
52)   unsigned int i;
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

53)   for (i = 0; i < count(ip_buffer_tab); i++)
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

54)     ip_buffer_tab[i].pkg_sz = 0;
55) }
56) 
57) /// tick procedure - call every 200ms
58) void ip_tick200(void)
59) {
60)   unsigned int i;
61) 
62)   // increase age of buffered IP packets and remove timed out ones
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

63)   for (i = 0; i < count(ip_buffer_tab); i++) {
64)     if (ip_buffer_tab[i].pkg_sz > 0) { // buffer in use
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

65)       ip_buffer_tab[i].ticks++; // increase age
66)       if (ip_buffer_tab[i].ticks > IP_BUFFER_TICKS_MAX) // too old
67)         ip_buffer_tab[i].pkg_sz = 0; // discard packet
68)     }
69)   }
70) }
71) 
72) /**
73)  * @brief process a received IP packet
74)  * @param[in] ptr pointer to data of packet
75)  * @param[in] sz size of packet
76)  */
77) void ip_recv(void *ptr, unsigned int sz)
78) {
79)   struct ip_packet *ip_pack;
80)   unsigned int len;
81) 
82)   // packet too short
83)   if (sz < sizeof(struct ip_packet))
84)     return;
85) 
86)   ip_pack = ptr;
87) 
88)   // not IPv4 -> drop
89)   if (ip_pack->ip_hdr.ver__hdr_len != 0x45) // IPv4 with no options present
90)     return;
91) 
92)   // not to own IP / broadcast -> drop
93)   while (1) {
94)     // own IP -> accept
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

95)     if (ip_eq(ip_pack->ip_hdr.dest, config_ip.ip))
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

96)       break;
97)     // local network's broadcast address -> accept
98)     if ((ip_pack->ip_hdr.dest[0] & config_ip.mask[0]) ==
99)           (config_ip.ip[0] & config_ip.mask[0]) &&
100)         (ip_pack->ip_hdr.dest[1] & config_ip.mask[1]) ==
101)           (config_ip.ip[1] & config_ip.mask[1]) &&
102)         (ip_pack->ip_hdr.dest[2] & config_ip.mask[2]) ==
103)           (config_ip.ip[2] & config_ip.mask[2]) &&
104)         (ip_pack->ip_hdr.dest[3] & config_ip.mask[3]) ==
105)           (config_ip.ip[3] & config_ip.mask[3]) &&
106)         (ip_pack->ip_hdr.dest[0] & ~config_ip.mask[0]) ==
107)           ~config_ip.mask[0] &&
108)         (ip_pack->ip_hdr.dest[1] & ~config_ip.mask[1]) ==
109)           ~config_ip.mask[1] &&
110)         (ip_pack->ip_hdr.dest[2] & ~config_ip.mask[2]) ==
111)           ~config_ip.mask[2] &&
112)         (ip_pack->ip_hdr.dest[3] & ~config_ip.mask[3]) ==
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

113)           ~config_ip.mask[3])
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

114)       break;
Stefan Schuermans typo

Stefan Schuermans authored 12 years ago

115)     // link local broadcast address -> accept
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

116)     if (ip_pack->ip_hdr.dest[0] == 0xFF &&
117)         ip_pack->ip_hdr.dest[1] == 0xFF &&
118)         ip_pack->ip_hdr.dest[2] == 0xFF &&
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

119)         ip_pack->ip_hdr.dest[3] == 0xFF)
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

120)       break;
121)     // drop
122)     return;
123)   }
124) 
125)   // ignore packets sent from invalid source adresses
126)   //  - this might be some attack or some router fault
127)   if (ip_pack->ip_hdr.src[0] >= 0xE0 || // broadcast, reserved or multicast
128)       ip_pack->ip_hdr.src[0] == 0x7F || // loopback network
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

129)       ip_eq(ip_pack->ip_hdr.src, "\x00\x00\x00\x00")) // IP 0.0.0.0
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

130)     return;
131)   // ignore packets sent from local network or broadcast address
132)   if ((ip_pack->ip_hdr.src[0] & config_ip.mask[0]) ==
133)         (config_ip.ip[0] & config_ip.mask[0]) && // source IP is in own subnet
134)       (ip_pack->ip_hdr.src[1] & config_ip.mask[1]) ==
135)         (config_ip.ip[1] & config_ip.mask[1]) &&
136)       (ip_pack->ip_hdr.src[2] & config_ip.mask[2]) ==
137)         (config_ip.ip[2] & config_ip.mask[2]) &&
138)       (ip_pack->ip_hdr.src[3] & config_ip.mask[3]) ==
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

139)         (config_ip.ip[3] & config_ip.mask[3])) {
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

140)     // local network address
141)     if ((ip_pack->ip_hdr.src[0] & ~config_ip.mask[0]) == 0x00 &&
142)         (ip_pack->ip_hdr.src[1] & ~config_ip.mask[1]) == 0x00 &&
143)         (ip_pack->ip_hdr.src[2] & ~config_ip.mask[2]) == 0x00 &&
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

144)         (ip_pack->ip_hdr.src[3] & ~config_ip.mask[3]) == 0x00)
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

145)       return;
146)     // local broadcast address
147)     if ((ip_pack->ip_hdr.src[0] & ~config_ip.mask[0]) == 0xFF &&
148)         (ip_pack->ip_hdr.src[1] & ~config_ip.mask[1]) == 0xFF &&
149)         (ip_pack->ip_hdr.src[2] & ~config_ip.mask[2]) == 0xFF &&
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

150)         (ip_pack->ip_hdr.src[3] & ~config_ip.mask[3]) == 0xFF)
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

151)       return;
152)   }
153)   // ignore packets sent from own IP address
154)   if (ip_eq(ip_pack->ip_hdr.src, config_ip.ip))
155)     return;
156) 
157)   // ignore fragmented packets
158)   // BUG: fragmentation must be supported according to RFC781
159)   //      but there is not enough RAM for assembling packets with up to 64kB
160)   // fragment offset 0, more_frags=0, dont_frag=x, reserved_flag=0
161)   if ((ntohs(ip_pack->ip_hdr.frag_ofs) & 0xBFFF) != 0x0000)
162)     return;
163) 
164)   // check total length
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

165)   len = sizeof(struct ethernet_header) + ntohs(ip_pack->ip_hdr.total_len);
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

166)   if (sz < len) // packet is truncated
167)     return;
168)   sz = len; // remove ethernet padding from packet (maybe sz > len)
169) 
170)   // test header checksum
171)   if (checksum(&ip_pack->ip_hdr, sizeof(struct ip_header), 0x0000, 0x0000))
172)     return;
173) 
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

174)   // save MAC/IP information in ARP table
175)   arp_store(ip_pack->ip_hdr.src, ip_pack->eth_hdr.src);
176) 
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

177)   // branch according to protocol
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

178)   switch (ip_pack->ip_hdr.proto) {
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

179)     // ICMP
180)     case 0x01:
181)       icmp_recv(ptr, sz);
182)       break;
183)     // UDP
184)     case 0x11:
185)       udp_recv(ptr, sz);
186)       break;
187)   }
188) }
189) 
190) /**
191)  * @brief send an IP packet
192)  * @param[in] ptr pointer to data of packet
193)  * @param[in] sz size of packet
194)  *
Stefan Schuermans handle padding to minimum e...

Stefan Schuermans authored 12 years ago

195)  * ptr must point to a ip_packet
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

196)  * with ip_hdr.proto and ip_hdr.dest already initialized
197)  */
198) void ip_send(void *ptr, unsigned int sz)
199) {
200)   struct ip_packet *ip_pack;
201)   unsigned short chk;
202)   unsigned int i;
203) 
204)   // packet too short
205)   if (sz < sizeof(struct ip_packet))
206)     return;
207) 
208)   ip_pack = ptr;
209) 
210)   // fill in header values
211)   ip_pack->ip_hdr.ver__hdr_len = 0x45;
212)   ip_pack->ip_hdr.tos = 0x00;
213)   ip_pack->ip_hdr.total_len = htons(sz - sizeof(struct ethernet_header));
214)   ip_pack->ip_hdr.id = 0x0000;
215)   ip_pack->ip_hdr.frag_ofs = 0x0000;
216)   ip_pack->ip_hdr.ttl = 0x40;
217)   ip_pack->ip_hdr.hdr_chk = 0x0000;
218)   ip_cpy(ip_pack->ip_hdr.src, config_ip.ip);
219) 
220)   // generate header checksum
221)   chk = checksum(&ip_pack->ip_hdr, sizeof(struct ip_header), 0x0000, 0x0000);
222)   ip_pack->ip_hdr.hdr_chk = htons(chk);
223) 
224)   // destination is in own subnet
225)   if ((ip_pack->ip_hdr.dest[0] & config_ip.mask[0]) ==
226)         (config_ip.ip[0] & config_ip.mask[0]) &&
227)       (ip_pack->ip_hdr.dest[1] & config_ip.mask[1]) ==
228)         (config_ip.ip[1] & config_ip.mask[1]) &&
229)       (ip_pack->ip_hdr.dest[2] & config_ip.mask[2]) ==
230)         (config_ip.ip[2] & config_ip.mask[2]) &&
231)       (ip_pack->ip_hdr.dest[3] & config_ip.mask[3]) ==
Stefan Schuermans add support for broadcasts,...

Stefan Schuermans authored 12 years ago

232)         (config_ip.ip[3] & config_ip.mask[3])) {
233)     // broadcast
234)     if ((ip_pack->ip_hdr.dest[0] | config_ip.mask[0]) == 0xFF &&
235)         (ip_pack->ip_hdr.dest[1] | config_ip.mask[1]) == 0xFF &&
236)         (ip_pack->ip_hdr.dest[2] | config_ip.mask[2]) == 0xFF &&
237)         (ip_pack->ip_hdr.dest[3] | config_ip.mask[3]) == 0xFF) {
238)       mac_cpy(ip_pack->eth_hdr.dest, "\xFF\xFF\xFF\xFF\xFF\xFF");
239)       i = 0; // MAC is available
240)     }
241)     // unicast
242)     else {
243)       // lookup MAC address of destination
244)       i = arp_lookup(ip_pack->ip_hdr.dest, ip_pack->eth_hdr.dest);
245)     }
246)   }
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

247)   // destination is not in own subnet
Stefan Schuermans add support for broadcasts,...

Stefan Schuermans authored 12 years ago

248)   else {
249)     // broadcast
250)     if (ip_pack->ip_hdr.dest[0] == 0xFF &&
251)         ip_pack->ip_hdr.dest[1] == 0xFF &&
252)         ip_pack->ip_hdr.dest[2] == 0xFF &&
253)         ip_pack->ip_hdr.dest[3] == 0xFF) {
254)       mac_cpy(ip_pack->eth_hdr.dest, "\xFF\xFF\xFF\xFF\xFF\xFF");
255)       i = 0; // MAC is available
256)     }
257)     // unicast
258)     else {
259)       // lookup MAC address of default gateway
260)       i = arp_lookup(config_ip.gw, ip_pack->eth_hdr.dest);
261)     }
262)   }
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

263) 
264)   // MAC available
265)   if (i == 0x00) {
Stefan Schuermans add support for broadcasts,...

Stefan Schuermans authored 12 years ago

266)     // send IP packet
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

267)     ip_pack->eth_hdr.type = htons(0x0800); // ethernet packet type: IP
268)     ethernet_send(ip_pack, sz);
269)     return;
270)   }
271) 
272)   // find a buffer to store the packet in
273)   for (i = 0; i < count(ip_buffer_tab); i++) {
274)     if (ip_buffer_tab[i].pkg_sz == 0 && // buffer not in use
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

275)         sz <= ip_buffer_tab[i].buf_sz) { // buffer long enough
Stefan Schuermans implemented IP + ICMP, fixe...

Stefan Schuermans authored 12 years ago

276)       // put packet into buffer
277)       memcpy(ip_buffer_tab[i].ptr, ptr, sz);
278)       ip_buffer_tab[i].pkg_sz = sz;
279)       ip_buffer_tab[i].ticks = 0;
280)       break;
281)     }
282)   }
283)   /* if no buffer was found, we cannnot do anything about it
284)      and must discard the packet (i.e. do nothing here) */
285) }
286) 
287) /**
288)  * @brief a MAC address was discovered
289)  * @param[in] ip the IP address the MAC was discovered for
290)  * @param[in] mac the MAC address corresponding to the IP address
291)  *
292)  * called by ARP to notify IP
293)  */
294) void ip_got_mac(unsigned char ip[4], unsigned char mac[6])
295) {
296)   unsigned char i;
297)   struct ip_packet *ip_pack;
298) 
299)   // search for buffered packets that can be sent now
300)   for (i = 0; i < count(ip_buffer_tab); i++) {
301)     if (ip_buffer_tab[i].pkg_sz > 0) { // buffer in use
302)       ip_pack = ip_buffer_tab[i].ptr;
303) 
304)       // destination is in own subnet
305)       if ((ip_pack->ip_hdr.dest[0] & config_ip.mask[0]) ==
306)             (config_ip.ip[0] & config_ip.mask[0]) &&
307)           (ip_pack->ip_hdr.dest[1] & config_ip.mask[1]) ==
308)             (config_ip.ip[1] & config_ip.mask[1]) &&
309)           (ip_pack->ip_hdr.dest[2] & config_ip.mask[2]) ==
310)             (config_ip.ip[2] & config_ip.mask[2]) &&
311)           (ip_pack->ip_hdr.dest[3] & config_ip.mask[3]) ==
312)             (config_ip.ip[3] & config_ip.mask[3])) {
313)         // packet can be sent to destination
Stefan Schuermans use implicit MAC/IP informa...

Stefan Schuermans authored 12 years ago

314)         if (ip_eq(ip_pack->ip_hdr.dest, ip)) {