implemented IP + ICMP, fixed ARP (padding overwriting stack)
Stefan Schuermans

Stefan Schuermans commited on 2012-03-24 13:58:46
Showing 17 changed files, with 792 additions and 50 deletions.

... ...
@@ -4,7 +4,7 @@ PERL=perl
4 4
 CC=mipsel-elf-gcc
5 5
 LD=mipsel-elf-ld
6 6
 OBJCOPY=mipsel-elf-objcopy
7
-CFLAGS=-Wall -Wextra -mips1 -mno-abicalls -Os
7
+CFLAGS=-Wall -Wextra -fno-builtin -mips1 -mno-abicalls -Os
8 8
 LFLAGS=-mips1
9 9
 
10 10
 BASES=$(patsubst %.c,%,$(SRCS))
... ...
@@ -1,7 +1,7 @@
1 1
 #include "arp.h"
2 2
 #include "config.h"
3 3
 #include "ethernet.h"
4
-// TODO #include "ip.h"
4
+#include "ip.h"
5 5
 #include "macros.h"
6 6
 #include "nethelp.h"
7 7
 
... ...
@@ -30,28 +30,28 @@ struct arp_table
30 30
  */
31 31
 static void arp_send_request(unsigned char ip[4])
32 32
 {
33
-  struct arp_packet arp_request;
33
+  struct arp_packet_pad arp_request;
34 34
 
35 35
   // build ARP request
36
-  arp_request.arp_hdr.hw_type = htons(0x0001); // ethernet
37
-  arp_request.arp_hdr.proto_type = htons(0x0800); // IP
38
-  arp_request.arp_hdr.hw_len = 0x06; // length of a MAC address
39
-  arp_request.arp_hdr.proto_len = 0x04; // length of an IP address
40
-  arp_request.arp_hdr.op = htons(0x0001); // ARP request
41
-  mac_cpy(arp_request.arp_hdr.src_mac, config_mac.mac); // own MAC
42
-  ip_cpy(arp_request.arp_hdr.src_ip, config_ip.ip); // own IP
43
-  mac_cpy(arp_request.arp_hdr.dest_mac,
36
+  arp_request.p.arp_hdr.hw_type = htons(0x0001); // ethernet
37
+  arp_request.p.arp_hdr.proto_type = htons(0x0800); // IP
38
+  arp_request.p.arp_hdr.hw_len = 0x06; // length of a MAC address
39
+  arp_request.p.arp_hdr.proto_len = 0x04; // length of an IP address
40
+  arp_request.p.arp_hdr.op = htons(0x0001); // ARP request
41
+  mac_cpy(arp_request.p.arp_hdr.src_mac, config_mac.mac); // own MAC
42
+  ip_cpy(arp_request.p.arp_hdr.src_ip, config_ip.ip); // own IP
43
+  mac_cpy(arp_request.p.arp_hdr.dest_mac,
44 44
           "\xFF\xFF\xFF\xFF\xFF\xFF"); // broadcast MAC
45
-  ip_cpy(arp_request.arp_hdr.dest_ip, ip); // requested IP
45
+  ip_cpy(arp_request.p.arp_hdr.dest_ip, ip); // requested IP
46 46
 
47 47
   // send ARP request
48
-  mac_cpy(arp_request.eth_hdr.dest, arp_request.arp_hdr.dest_mac);
49
-  arp_request.eth_hdr.type = htons(0x0806); // ethernet packet type: ARP
50
-  ethernet_send(&arp_request, sizeof(arp_request));
48
+  mac_cpy(arp_request.p.eth_hdr.dest, arp_request.p.arp_hdr.dest_mac);
49
+  arp_request.p.eth_hdr.type = htons(0x0806); // ethernet packet type: ARP
50
+  ethernet_send(&arp_request.p, sizeof(arp_request.p));
51 51
 }
52 52
 
53 53
 /// initialize
54
-/* extern */ void arp_init(void)
54
+void arp_init(void)
55 55
 {
56 56
   unsigned int i;
57 57
 
... ...
@@ -61,7 +61,7 @@ static void arp_send_request(unsigned char ip[4])
61 61
 }
62 62
 
63 63
 /// tick procedure - call every 200ms
64
-/* extern */ void arp_tick200(void)
64
+void arp_tick200(void)
65 65
 {
66 66
   unsigned int i;
67 67
 
... ...
@@ -91,7 +91,7 @@ static void arp_send_request(unsigned char ip[4])
91 91
  * @param[in] ptr pointer to data of packet
92 92
  * @param[in] sz size of packet
93 93
  */
94
-/* extern */ void arp_recv(void *ptr, unsigned int sz)
94
+void arp_recv(void *ptr, unsigned int sz)
95 95
 {
96 96
   struct arp_packet *arp_pack;
97 97
 
... ...
@@ -99,7 +99,7 @@ static void arp_send_request(unsigned char ip[4])
99 99
   if (sz < sizeof(struct arp_packet))
100 100
     return;
101 101
 
102
-  arp_pack = (struct arp_packet *)ptr;
102
+  arp_pack = ptr;
103 103
 
104 104
   // not IP over ethernet
105 105
   if (arp_pack->arp_hdr.hw_type != htons(0x0001) || // ethernet
... ...
@@ -135,7 +135,7 @@ static void arp_send_request(unsigned char ip[4])
135 135
     mac_cpy(arp_reply.p.eth_hdr.dest,
136 136
             arp_reply.p.arp_hdr.dest_mac); // ethernet destination address
137 137
     arp_reply.p.eth_hdr.type = htons(0x0806); // ethernet packet type: ARP
138
-    ethernet_send(&arp_reply, sizeof(arp_reply));
138
+    ethernet_send(&arp_reply.p, sizeof(arp_reply.p));
139 139
 
140 140
     return;
141 141
   }
... ...
@@ -161,7 +161,7 @@ static void arp_send_request(unsigned char ip[4])
161 161
       mac_cpy(arp_tab[i].mac, arp_pack->arp_hdr.src_mac);
162 162
       // notify IP
163 163
       //  - IP might be waiting for the MAC to transmit a packet
164
-      // TODO ip_got_mac(arp_tab[i].ip, arp_tab[i].mac);
164
+      ip_got_mac(arp_tab[i].ip, arp_tab[i].mac);
165 165
     }
166 166
     return;
167 167
   }
... ...
@@ -174,7 +174,7 @@ static void arp_send_request(unsigned char ip[4])
174 174
  * @param[out] mac MAC address for this IP address
175 175
  * @return 0 in case of success, 1 if the MAC address is unknown
176 176
  */
177
-/* extern */ int arp_lookup(unsigned char ip[4], unsigned char mac[6])
177
+int arp_lookup(unsigned char ip[4], unsigned char mac[6])
178 178
 {
179 179
   unsigned int i, j;
180 180
 
... ...
@@ -28,17 +28,17 @@ struct arp_packet
28 28
 ETHERNET_PAD(arp_packet);
29 29
 
30 30
 /// initialize
31
-extern void arp_init(void);
31
+void arp_init(void);
32 32
 
33 33
 /// tick procedure - call every 200ms
34
-extern void arp_tick200(void);
34
+void arp_tick200(void);
35 35
 
36 36
 /**
37 37
  * @brief process a received ARP packet
38 38
  * @param[in] ptr pointer to data of packet
39 39
  * @param[in] sz size of packet
40 40
  */
41
-extern void arp_recv(void *ptr, unsigned int sz);
41
+void arp_recv(void *ptr, unsigned int sz);
42 42
 
43 43
 /**
44 44
  * @brief look up the MAC for an IP address
... ...
@@ -46,7 +46,7 @@ extern void arp_recv(void *ptr, unsigned int sz);
46 46
  * @param[out] mac MAC address for this IP address
47 47
  * @return 0 in case of success, 1 if the MAC address is unknown
48 48
  */
49
-extern int arp_lookup(unsigned char ip[4], unsigned char mac[6]);
49
+int arp_lookup(unsigned char ip[4], unsigned char mac[6]);
50 50
 
51 51
 #endif // #ifdef ARP_H
52 52
 
... ...
@@ -0,0 +1,41 @@
1
+#include "checksum.h"
2
+#include "macros.h"
3
+#include "nethelp.h"
4
+
5
+/**
6
+ * @brief generate an IP style checksum
7
+ * @param[in] ptr pointer to data
8
+ * @param[in] sz size of data
9
+ * @param[in] pseudo1 additional value to include - set to 0 if not needed
10
+ * @param[in] preude2 additional value to include - set to 0 if not needed
11
+ *
12
+ * can also be used to check a checksum (returns 0 if correct)
13
+ */
14
+unsigned short checksum(void *ptr, unsigned int sz,
15
+                        unsigned short pseudo1, unsigned short pseudo2)
16
+{
17
+  unsigned int sum;
18
+  unsigned short *data;
19
+
20
+  // sum up data of pseudo header
21
+  sum = pseudo1;
22
+  sum += pseudo2;
23
+
24
+  // add full 16 bit words in header
25
+  for (data = ptr; sz >= 2; data++, sz -= 2)
26
+    sum += ntohs(*data);
27
+
28
+  // add last byte
29
+  if (sz >= 1)
30
+    sum += *(unsigned char *)data << 8;
31
+
32
+  // convert sum to one's complement sum
33
+  //   add carries (bits 31..16) to sum (bits 15..0)
34
+  sum = (sum & 0x0000FFFF) + (sum >> 16);
35
+  //   still a carry possible (from last addition)
36
+  sum = (sum & 0x0000FFFF) + (sum >> 16);
37
+
38
+  // return complement of one's complement sum
39
+  return ~(unsigned short)sum;
40
+}
41
+
... ...
@@ -0,0 +1,17 @@
1
+#ifndef CHECKSUM_H
2
+#define CHECKSUM_H
3
+
4
+/**
5
+ * @brief generate an IP style checksum
6
+ * @param[in] ptr pointer to data
7
+ * @param[in] sz size of data
8
+ * @param[in] pseudo1 additional value to include - set to 0 if not needed
9
+ * @param[in] preude2 additional value to include - set to 0 if not needed
10
+ *
11
+ * can also be used to check a checksum (returns 0 if correct)
12
+ */
13
+unsigned short checksum(void *ptr, unsigned int sz,
14
+                        unsigned short pseudo1, unsigned short pseudo2);
15
+
16
+#endif // #ifdef CHECKSUM_H
17
+
... ...
@@ -8,7 +8,7 @@
8 8
 #include "config.h"
9 9
 #include "eth.h"
10 10
 #include "ethernet.h"
11
-// TODO #include "ip.h"
11
+#include "ip.h"
12 12
 #include "macros.h"
13 13
 #include "nethelp.h"
14 14
 
... ...
@@ -17,7 +17,7 @@
17 17
  * @param[in] ptr pointer to data of packet
18 18
  * @param[in] sz size of packet
19 19
  */
20
-/* extern */ void ethernet_recv(void *ptr, unsigned int sz)
20
+void ethernet_recv(void *ptr, unsigned int sz)
21 21
 {
22 22
   struct ethernet_packet *eth_pack;
23 23
 
... ...
@@ -25,7 +25,7 @@
25 25
   if (sz < sizeof(struct ethernet_packet))
26 26
     return;
27 27
 
28
-  eth_pack = (struct ethernet_packet *)ptr;
28
+  eth_pack = ptr;
29 29
 
30 30
   // branch according to packet type
31 31
   switch (eth_pack->eth_hdr.type)
... ...
@@ -36,7 +36,7 @@
36 36
       break;
37 37
     // IP
38 38
     case htons(0x0800):
39
-      // TODO ip_recv(ptr, sz);
39
+      ip_recv(ptr, sz);
40 40
       break;
41 41
   }
42 42
 }
... ...
@@ -46,10 +46,10 @@
46 46
  * @param[in] ptr pointer to data of packet
47 47
  * @param[in] sz size of packet
48 48
  *
49
- * ptr must point to a ethernet_packet with eth_hdr.dest and eth_hdr.type
50
- * already initialized
49
+ * ptr must point to a ethernet_packet of sufficient size (ethernet padding)
50
+ * with eth_hdr.dest and eth_hdr.type already initialized
51 51
  */
52
-/* extern */ void ethernet_send(void *ptr, unsigned int sz)
52
+void ethernet_send(void *ptr, unsigned int sz)
53 53
 {
54 54
   struct ethernet_packet *eth_pack;
55 55
 
... ...
@@ -57,7 +57,7 @@
57 57
   if (sz < sizeof(struct ethernet_packet))
58 58
     return;
59 59
 
60
-  eth_pack = (struct ethernet_packet *)ptr;
60
+  eth_pack = ptr;
61 61
 
62 62
   // fill in source address
63 63
   mac_cpy(eth_pack->eth_hdr.src, config_mac.mac);
... ...
@@ -43,8 +43,8 @@ void ethernet_recv(void *ptr, unsigned int sz);
43 43
  * @param[in] ptr pointer to data of packet
44 44
  * @param[in] sz size of packet
45 45
  *
46
- * ptr must point to a ethernet_packet with eth_hdr.dest and eth_hdr.type
47
- * already initialized
46
+ * ptr must point to a ethernet_packet of sufficient size (ethernet padding)
47
+ * with eth_hdr.dest and eth_hdr.type already initialized
48 48
  */
49 49
 void ethernet_send(void *ptr, unsigned int sz);
50 50
 
... ...
@@ -0,0 +1,101 @@
1
+#include "checksum.h"
2
+#include "ethernet.h"
3
+#include "icmp.h"
4
+#include "ip.h"
5
+#include "macros.h"
6
+#include "nethelp.h"
7
+
8
+/**
9
+ * @brief send an ICMP packet
10
+ * @param[in] ptr pointer to data of packet
11
+ * @param[in] sz size of packet
12
+ *
13
+ * ptr must point to a icmp_packet of sufficient size (ethernet padding)
14
+ * with icmp_hdr.type, icmp_hdr.code and ip_hdr.sest already initialized
15
+ */
16
+static void icmp_send(void *ptr, unsigned int sz)
17
+{
18
+  struct icmp_packet *icmp_pack;
19
+  unsigned short chk;
20
+
21
+  // packet too short
22
+  if (sz < sizeof(struct icmp_packet))
23
+    return;
24
+
25
+  icmp_pack = ptr;
26
+
27
+  // fill in header values
28
+  icmp_pack->icmp_hdr.chk = 0x0000;
29
+
30
+  // generate checksum
31
+  chk = checksum(&icmp_pack->icmp_hdr,
32
+                 sz - sizeof(struct ethernet_header)
33
+                    - sizeof(struct ip_header),
34
+                 0x0000, 0x0000);
35
+  icmp_pack->icmp_hdr.chk = htons(chk);
36
+
37
+  // send ICMP packet
38
+  icmp_pack->ip_hdr.proto = 0x01; // ICMP
39
+  ip_send(icmp_pack, sz);
40
+}
41
+
42
+/**
43
+ * @brief process a received ICMP echo request packet
44
+ * @param[in] ptr pointer to data of packet
45
+ * @param[in] sz size of packet
46
+ */
47
+static void icmp_echo_req_recv(void *ptr, unsigned int sz)
48
+{
49
+  struct icmp_echo_packet *icmp_echo_pack;
50
+
51
+  // packet too short
52
+  if (sz < sizeof(struct icmp_echo_packet))
53
+    return;
54
+
55
+  icmp_echo_pack = ptr;
56
+
57
+  // code not 0
58
+  if (icmp_echo_pack->icmp_hdr.code != 0x00)
59
+    return;
60
+
61
+  // send an ICMP echo reply
62
+  //  - use same buffer to send reply
63
+  //  - this saves us from needing to allocate a new buffer
64
+  //  - this saves us from needing to copy echo_hdr.id, echo_hdr.seq and data
65
+  icmp_echo_pack->icmp_hdr.type = 0x00; // ICMP echo reply
66
+  icmp_echo_pack->icmp_hdr.code = 0x00;
67
+  //   destination IP is source IP of request
68
+  ip_cpy(icmp_echo_pack->ip_hdr.dest, icmp_echo_pack->ip_hdr.src);
69
+  icmp_send(icmp_echo_pack, sz);
70
+}
71
+
72
+/**
73
+ * @brief process a received ICMP packet
74
+ * @param[in] ptr pointer to data of packet
75
+ * @param[in] sz size of packet
76
+ */
77
+void icmp_recv(void *ptr, unsigned int sz)
78
+{
79
+  struct icmp_packet *icmp_pack;
80
+
81
+  // packet too short
82
+  if (sz < sizeof(struct icmp_packet))
83
+    return;
84
+
85
+  icmp_pack = ptr;
86
+
87
+  // test checksum
88
+  if (checksum(&icmp_pack->icmp_hdr,
89
+               sz - sizeof(struct ethernet_header) - sizeof(struct ip_header),
90
+               0x0000, 0x0000))
91
+    return;
92
+
93
+  // branch according to type
94
+  switch (icmp_pack->icmp_hdr.type) {
95
+    // ICMP echo request
96
+    case 0x08:
97
+      icmp_echo_req_recv(ptr, sz);
98
+      break;
99
+  }
100
+}
101
+
... ...
@@ -0,0 +1,53 @@
1
+#ifndef ICMP_H
2
+#define ICMP_H
3
+
4
+#include "ethernet.h"
5
+#include "ip.h"
6
+
7
+/// header of ICMP packet
8
+struct icmp_header
9
+{
10
+  unsigned char type;
11
+  unsigned char code;
12
+  unsigned short chk;
13
+} __attribute__((packed));
14
+
15
+/// ICMP packet
16
+struct icmp_packet
17
+{
18
+  struct ethernet_header eth_hdr;
19
+  struct ip_header ip_hdr;
20
+  struct icmp_header icmp_hdr;
21
+} __attribute__((packed));
22
+
23
+/// ICMP packet with padding
24
+ETHERNET_PAD(icmp_packet);
25
+
26
+// header of ICMP echo request/reply packet
27
+struct icmp_echo_header
28
+{
29
+  unsigned short id;
30
+  unsigned short seq;
31
+} __attribute__((packed));
32
+
33
+/// ICMP echo request/reply packet
34
+struct icmp_echo_packet
35
+{
36
+  struct ethernet_header eth_hdr;
37
+  struct ip_header ip_hdr;
38
+  struct icmp_header icmp_hdr;
39
+  struct icmp_echo_header echo_hdr;
40
+} __attribute__((packed));
41
+
42
+/// ICMP echo request/reply packet with padding
43
+ETHERNET_PAD(icmp_echo_packet);
44
+
45
+/**
46
+ * @brief process a received ICMP packet
47
+ * @param[in] ptr pointer to data of packet
48
+ * @param[in] sz size of packet
49
+ */
50
+void icmp_recv(void *ptr, unsigned int sz);
51
+
52
+#endif // #ifdef ICMP_H
53
+
... ...
@@ -0,0 +1,307 @@
1
+#include "arp.h"
2
+#include "checksum.h"
3
+#include "config.h"
4
+#include "ethernet.h"
5
+#include "icmp.h"
6
+#include "ip.h"
7
+#include "macros.h"
8
+#include "memcpy.h"
9
+#include "nethelp.h"
10
+#include "udp.h"
11
+
12
+// timing parameters
13
+#define IP_BUFFER_TICKS_MAX 50 // maximum age of buffered IP packet (in 200ms)
14
+
15
+/**
16
+ * buffers for IP packets to transmit
17
+ *  - used if MAC is unknown when packet shall be transmitted
18
+ *  - packet is sent when MAC becomes known
19
+ *  - some buffers with different length (packets have different lengths)
20
+ *  - all buffers must be larger than min ethernet frame size (eth padding)
21
+ */
22
+//@{
23
+unsigned int ip_buffer0[20];
24
+unsigned int ip_buffer1[20];
25
+unsigned int ip_buffer2[40];
26
+unsigned int ip_buffer3[80];
27
+//@}
28
+/// table with buffers
29
+struct ip_buffer_table
30
+{
31
+  void *ptr; ///< pointer to buffer for packet
32
+  unsigned int buf_sz; ///< size of buffer
33
+  unsigned int pkg_sz; ///< size of packet in buffer, 0 for packet
34
+  unsigned int ticks; //< age of entry (in 200ms)
35
+} ip_buffer_tab[] =
36
+{ // put smaller buffers in front of larger buffers
37
+  //  - then short packets will use smaller buffers more often
38
+  { ip_buffer0, sizeof(ip_buffer0), 0, 0 },
39
+  { ip_buffer1, sizeof(ip_buffer1), 0, 0 },
40
+  { ip_buffer2, sizeof(ip_buffer2), 0, 0 },
41
+  { ip_buffer3, sizeof(ip_buffer3), 0, 0 },
42
+};
43
+
44
+/// initialize
45
+void ip_init(void)
46
+{
47
+  unsigned int i;
48
+  for (i = 0; i < count(ip_buffer_tab ); i++)
49
+    ip_buffer_tab[i].pkg_sz = 0;
50
+}
51
+
52
+/// tick procedure - call every 200ms
53
+void ip_tick200(void)
54
+{
55
+  unsigned int i;
56
+
57
+  // increase age of buffered IP packets and remove timed out ones
58
+  for (i = 0; i < count( ip_buffer_tab ); i++) {
59
+    if (ip_buffer_tab[i].pkg_sz > 0 ) { // buffer in use
60
+      ip_buffer_tab[i].ticks++; // increase age
61
+      if (ip_buffer_tab[i].ticks > IP_BUFFER_TICKS_MAX) // too old
62
+        ip_buffer_tab[i].pkg_sz = 0; // discard packet
63
+    }
64
+  }
65
+}
66
+
67
+/**
68
+ * @brief process a received IP packet
69
+ * @param[in] ptr pointer to data of packet
70
+ * @param[in] sz size of packet
71
+ */
72
+void ip_recv(void *ptr, unsigned int sz)
73
+{
74
+  struct ip_packet *ip_pack;
75
+  unsigned int len;
76
+
77
+  // packet too short
78
+  if (sz < sizeof(struct ip_packet))
79
+    return;
80
+
81
+  ip_pack = ptr;
82
+
83
+  // not IPv4 -> drop
84
+  if (ip_pack->ip_hdr.ver__hdr_len != 0x45) // IPv4 with no options present
85
+    return;
86
+
87
+  // not to own IP / broadcast -> drop
88
+  while (1) {
89
+    // own IP -> accept
90
+    if (ip_eq(ip_pack->ip_hdr.dest, config_ip.ip) )
91
+      break;
92
+    // local network's broadcast address -> accept
93
+    if ((ip_pack->ip_hdr.dest[0] & config_ip.mask[0]) ==
94
+          (config_ip.ip[0] & config_ip.mask[0]) &&
95
+        (ip_pack->ip_hdr.dest[1] & config_ip.mask[1]) ==
96
+          (config_ip.ip[1] & config_ip.mask[1]) &&
97
+        (ip_pack->ip_hdr.dest[2] & config_ip.mask[2]) ==
98
+          (config_ip.ip[2] & config_ip.mask[2]) &&
99
+        (ip_pack->ip_hdr.dest[3] & config_ip.mask[3]) ==
100
+          (config_ip.ip[3] & config_ip.mask[3]) &&
101
+        (ip_pack->ip_hdr.dest[0] & ~config_ip.mask[0]) ==
102
+          ~config_ip.mask[0] &&
103
+        (ip_pack->ip_hdr.dest[1] & ~config_ip.mask[1]) ==
104
+          ~config_ip.mask[1] &&
105
+        (ip_pack->ip_hdr.dest[2] & ~config_ip.mask[2]) ==
106
+          ~config_ip.mask[2] &&
107
+        (ip_pack->ip_hdr.dest[3] & ~config_ip.mask[3]) ==
108
+          ~config_ip.mask[3] )
109
+      break;
110
+    // link local boradcast address -> accept
111
+    if (ip_pack->ip_hdr.dest[0] == 0xFF &&
112
+        ip_pack->ip_hdr.dest[1] == 0xFF &&
113
+        ip_pack->ip_hdr.dest[2] == 0xFF &&
114
+        ip_pack->ip_hdr.dest[3] == 0xFF )
115
+      break;
116
+    // drop
117
+    return;
118
+  }
119
+
120
+  // ignore packets sent from invalid source adresses
121
+  //  - this might be some attack or some router fault
122
+  if (ip_pack->ip_hdr.src[0] >= 0xE0 || // broadcast, reserved or multicast
123
+      ip_pack->ip_hdr.src[0] == 0x7F || // loopback network
124
+      ip_eq(ip_pack->ip_hdr.src, "\x00\x00\x00\x00" )) // IP 0.0.0.0
125
+    return;
126
+  // ignore packets sent from local network or broadcast address
127
+  if ((ip_pack->ip_hdr.src[0] & config_ip.mask[0]) ==
128
+        (config_ip.ip[0] & config_ip.mask[0]) && // source IP is in own subnet
129
+      (ip_pack->ip_hdr.src[1] & config_ip.mask[1]) ==
130
+        (config_ip.ip[1] & config_ip.mask[1]) &&
131
+      (ip_pack->ip_hdr.src[2] & config_ip.mask[2]) ==
132
+        (config_ip.ip[2] & config_ip.mask[2]) &&
133
+      (ip_pack->ip_hdr.src[3] & config_ip.mask[3]) ==
134
+        (config_ip.ip[3] & config_ip.mask[3]))
135
+  {
136
+    // local network address
137
+    if ((ip_pack->ip_hdr.src[0] & ~config_ip.mask[0]) == 0x00 &&
138
+        (ip_pack->ip_hdr.src[1] & ~config_ip.mask[1]) == 0x00 &&
139
+        (ip_pack->ip_hdr.src[2] & ~config_ip.mask[2]) == 0x00 &&
140
+        (ip_pack->ip_hdr.src[3] & ~config_ip.mask[3]) == 0x00 )
141
+      return;
142
+    // local broadcast address
143
+    if ((ip_pack->ip_hdr.src[0] & ~config_ip.mask[0]) == 0xFF &&
144
+        (ip_pack->ip_hdr.src[1] & ~config_ip.mask[1]) == 0xFF &&
145
+        (ip_pack->ip_hdr.src[2] & ~config_ip.mask[2]) == 0xFF &&
146
+        (ip_pack->ip_hdr.src[3] & ~config_ip.mask[3]) == 0xFF )
147
+      return;
148
+  }
149
+  // ignore packets sent from own IP address
150
+  if (ip_eq(ip_pack->ip_hdr.src, config_ip.ip))
151
+    return;
152
+
153
+  // ignore fragmented packets
154
+  // BUG: fragmentation must be supported according to RFC781
155
+  //      but there is not enough RAM for assembling packets with up to 64kB
156
+  // fragment offset 0, more_frags=0, dont_frag=x, reserved_flag=0
157
+  if ((ntohs(ip_pack->ip_hdr.frag_ofs) & 0xBFFF) != 0x0000)
158
+    return;
159
+
160
+  // check total length
161
+  len = sizeof(struct ethernet_header ) + ntohs(ip_pack->ip_hdr.total_len);
162
+  if (sz < len) // packet is truncated
163
+    return;
164
+  sz = len; // remove ethernet padding from packet (maybe sz > len)
165
+
166
+  // test header checksum
167
+  if (checksum(&ip_pack->ip_hdr, sizeof(struct ip_header), 0x0000, 0x0000))
168
+    return;
169
+
170
+  // branch according to protocol
171
+  switch(ip_pack->ip_hdr.proto) {
172
+    // ICMP
173
+    case 0x01:
174
+      icmp_recv(ptr, sz);
175
+      break;
176
+    // UDP
177
+    case 0x11:
178
+      udp_recv(ptr, sz);
179
+      break;
180
+  }
181
+}
182
+
183
+/**
184
+ * @brief send an IP packet
185
+ * @param[in] ptr pointer to data of packet
186
+ * @param[in] sz size of packet
187
+ *
188
+ * ptr must point to a ip_packet of sufficient size (ethernet padding)
189
+ * with ip_hdr.proto and ip_hdr.dest already initialized
190
+ */
191
+void ip_send(void *ptr, unsigned int sz)
192
+{
193
+  struct ip_packet *ip_pack;
194
+  unsigned short chk;
195
+  unsigned int i;
196
+
197
+  // packet too short
198
+  if (sz < sizeof(struct ip_packet))
199
+    return;
200
+
201
+  ip_pack = ptr;
202
+
203
+  // fill in header values
204
+  ip_pack->ip_hdr.ver__hdr_len = 0x45;
205
+  ip_pack->ip_hdr.tos = 0x00;
206
+  ip_pack->ip_hdr.total_len = htons(sz - sizeof(struct ethernet_header));
207
+  ip_pack->ip_hdr.id = 0x0000;
208
+  ip_pack->ip_hdr.frag_ofs = 0x0000;
209
+  ip_pack->ip_hdr.ttl = 0x40;
210
+  ip_pack->ip_hdr.hdr_chk = 0x0000;
211
+  ip_cpy(ip_pack->ip_hdr.src, config_ip.ip);
212
+
213
+  // generate header checksum
214
+  chk = checksum(&ip_pack->ip_hdr, sizeof(struct ip_header), 0x0000, 0x0000);
215
+  ip_pack->ip_hdr.hdr_chk = htons(chk);
216
+
217
+  // destination is in own subnet
218
+  if ((ip_pack->ip_hdr.dest[0] & config_ip.mask[0]) ==
219
+        (config_ip.ip[0] & config_ip.mask[0]) &&
220
+      (ip_pack->ip_hdr.dest[1] & config_ip.mask[1]) ==
221
+        (config_ip.ip[1] & config_ip.mask[1]) &&
222
+      (ip_pack->ip_hdr.dest[2] & config_ip.mask[2]) ==
223
+        (config_ip.ip[2] & config_ip.mask[2]) &&
224
+      (ip_pack->ip_hdr.dest[3] & config_ip.mask[3]) ==
225
+        (config_ip.ip[3] & config_ip.mask[3]) )
226
+    // lookup MAC address of destination
227
+    i = arp_lookup(ip_pack->ip_hdr.dest, ip_pack->eth_hdr.dest);
228
+  // destination is not in own subnet
229
+  else
230
+    // lookup MAC address of default gateway
231
+    i = arp_lookup(config_ip.gw, ip_pack->eth_hdr.dest);
232
+
233
+  // MAC available
234
+  if (i == 0x00) {
235
+    // sent IP packet
236
+    ip_pack->eth_hdr.type = htons(0x0800); // ethernet packet type: IP
237
+    ethernet_send(ip_pack, sz);
238
+    return;
239
+  }
240
+
241
+  // find a buffer to store the packet in
242
+  for (i = 0; i < count(ip_buffer_tab); i++) {
243
+    if (ip_buffer_tab[i].pkg_sz == 0 && // buffer not in use
244
+        sz < ip_buffer_tab[i].buf_sz) { // buffer long enough
245
+      // put packet into buffer
246
+      memcpy(ip_buffer_tab[i].ptr, ptr, sz);
247
+      ip_buffer_tab[i].pkg_sz = sz;
248
+      ip_buffer_tab[i].ticks = 0;
249
+      break;
250
+    }
251
+  }
252
+  /* if no buffer was found, we cannnot do anything about it
253
+     and must discard the packet (i.e. do nothing here) */
254
+}
255
+
256
+/**
257
+ * @brief a MAC address was discovered
258
+ * @param[in] ip the IP address the MAC was discovered for
259
+ * @param[in] mac the MAC address corresponding to the IP address
260
+ *
261
+ * called by ARP to notify IP
262
+ */
263
+void ip_got_mac(unsigned char ip[4], unsigned char mac[6])
264
+{
265
+  unsigned char i;
266
+  struct ip_packet *ip_pack;
267
+
268
+  // search for buffered packets that can be sent now
269
+  for (i = 0; i < count(ip_buffer_tab); i++) {
270
+    if (ip_buffer_tab[i].pkg_sz > 0) { // buffer in use
271
+      ip_pack = ip_buffer_tab[i].ptr;
272
+
273
+      // destination is in own subnet
274
+      if ((ip_pack->ip_hdr.dest[0] & config_ip.mask[0]) ==
275
+            (config_ip.ip[0] & config_ip.mask[0]) &&
276
+          (ip_pack->ip_hdr.dest[1] & config_ip.mask[1]) ==
277
+            (config_ip.ip[1] & config_ip.mask[1]) &&
278
+          (ip_pack->ip_hdr.dest[2] & config_ip.mask[2]) ==
279
+            (config_ip.ip[2] & config_ip.mask[2]) &&
280
+          (ip_pack->ip_hdr.dest[3] & config_ip.mask[3]) ==
281
+            (config_ip.ip[3] & config_ip.mask[3])) {
282
+        // packet can be sent to destination
283
+        if (ip_eq( ip_pack->ip_hdr.dest, ip)) {
284
+          // send IP packet
285
+          ip_pack->eth_hdr.type = htons(0x0800); // ethernet packet type: IP
286
+          mac_cpy(ip_pack->eth_hdr.dest, mac);
287
+          ethernet_send(ip_buffer_tab[i].ptr, ip_buffer_tab[i].pkg_sz);
288
+          // buffer is now free
289
+          ip_buffer_tab[i].pkg_sz = 0;
290
+        }
291
+      }
292
+      // destination is not in own subnet
293
+      else {
294
+        // packet can be sent to gateway
295
+        if (ip_eq(config_ip.gw, ip)) {
296
+          // send IP packet
297
+          ip_pack->eth_hdr.type = htons(0x0800); // ethernet packet type: IP
298
+          mac_cpy(ip_pack->eth_hdr.dest, mac);
299
+          ethernet_send(ip_buffer_tab[i].ptr, ip_buffer_tab[i].pkg_sz);
300
+          // buffer is now free
301
+          ip_buffer_tab[i].pkg_sz = 0;
302
+        }
303
+      }
304
+    }
305
+  } // for (i ...
306
+}
307
+
... ...
@@ -0,0 +1,64 @@
1
+#ifndef IP_H
2
+#define IP_H
3
+
4
+#include "ethernet.h"
5
+
6
+/// header of IP packet
7
+struct ip_header
8
+{
9
+  unsigned char ver__hdr_len;
10
+  unsigned char tos;
11
+  unsigned short total_len;
12
+  unsigned short id;
13
+  unsigned short frag_ofs;
14
+  unsigned char ttl;
15
+  unsigned char proto;
16
+  unsigned short hdr_chk;
17
+  unsigned char src[4];
18
+  unsigned char dest[4];
19
+} __attribute__((packed));
20
+
21
+/// IP packet
22
+struct ip_packet
23
+{
24
+  struct ethernet_header eth_hdr;
25
+  struct ip_header ip_hdr;
26
+} __attribute__((packed));
27
+
28
+/// IP packet with padding
29
+ETHERNET_PAD(ip_packet);
30
+
31
+/// initialize
32
+void ip_init(void);
33
+
34
+/// tick procedure - call every 200ms
35
+void ip_tick200(void);
36
+
37
+/**
38
+ * @brief process a received IP packet
39
+ * @param[in] ptr pointer to data of packet
40
+ * @param[in] sz size of packet
41
+ */
42
+void ip_recv(void *ptr, unsigned int sz);
43
+
44
+/**
45
+ * @brief send an IP packet
46
+ * @param[in] ptr pointer to data of packet
47
+ * @param[in] sz size of packet
48
+ *
49
+ * ptr must point to a ip_packet of sufficient size (ethernet padding)
50
+ * with ip_hdr.proto and ip_hdr.dest already initialized
51
+ */
52
+void ip_send(void *ptr, unsigned int sz);
53
+
54
+/**
55
+ * @brief a MAC address was discovered
56
+ * @param[in] ip the IP address the MAC was discovered for
57
+ * @param[in] mac the MAC address corresponding to the IP address
58
+ *
59
+ * called by ARP to notify IP
60
+ */
61
+void ip_got_mac(unsigned char ip[4], unsigned char mac[6]);
62
+
63
+#endif // #ifdef IP_H
64
+
... ...
@@ -1,10 +1,12 @@
1 1
 #include "arp.h"
2 2
 #include "cyc_cnt.h"
3 3
 #include "eth.h"
4
+#include "ip.h"
4 5
 #include "lcd.h"
5 6
 #include "leds.h"
6
-#include "uart.h"
7 7
 #include "switches.h"
8
+#include "uart.h"
9
+#include "udp.h"
8 10
 
9 11
 unsigned char leds_val = 0x88;
10 12
 
... ...
@@ -81,6 +83,8 @@ void tick200(void)
81 83
 {
82 84
   leds_tick200();
83 85
   arp_tick200();
86
+  ip_tick200();
87
+  udp_tick200();
84 88
 }
85 89
 
86 90
 int main()
... ...
@@ -116,6 +120,7 @@ int main()
116 120
   leds_set_state(0x08);
117 121
 
118 122
   arp_init();
123
+  ip_init();
119 124
 
120 125
   leds_set_state(0x10);
121 126
 
... ...
@@ -0,0 +1,35 @@
1
+#include "memcpy.h"
2
+
3
+/**
4
+ * @brief copy memory
5
+ * @param[in] dest pointer to destination buffer
6
+ * @param[in] src pointer to source data
7
+ * @param[in] sz size of data to copy
8
+ */
9
+void memcpy(void *dest, const void *src, unsigned int sz)
10
+{
11
+  unsigned int *dest4;
12
+  const unsigned int *src4;
13
+  unsigned int sz4;
14
+  unsigned char *dest1;
15
+  const unsigned char *src1;
16
+
17
+  // word aligned memory addresses -> fast copy
18
+  if (((unsigned int)dest & 3) == 0 && ((unsigned int)src & 3) == 0) {
19
+    dest4 = dest;
20
+    src4 = src;
21
+    for (sz4 = sz >> 2; sz4 > 0; --sz4)
22
+      *dest4++ = *src4++;
23
+    dest = dest4;
24
+    src = src4;
25
+    sz -= sz4;
26
+    // there might still be a few bytes to copy now
27
+  }
28
+
29
+  // safe and slow fallback: copy byte-wise
30
+  dest1 = dest;
31
+  src1 = src;
32
+  for ( ; sz > 0; --sz)
33
+    *dest1++ = *src1++;
34
+}
35
+
... ...
@@ -0,0 +1,13 @@
1
+#ifndef MEMCPY_H
2
+#define MEMCPY_H
3
+
4
+/**
5
+ * @brief copy memory
6
+ * @param[in] dest pointer to destination buffer
7
+ * @param[in] src pointer to source data
8
+ * @param[in] sz size of data to copy
9
+ */
10
+void memcpy(void *dest, const void *src, unsigned int sz);
11
+
12
+#endif // #ifdef MEMCPY_H
13
+
... ...
@@ -0,0 +1,42 @@
1
+#include "config.h"
2
+#include "checksum.h"
3
+#include "ethernet.h"
4
+#include "ip.h"
5
+#include "macros.h"
6
+#include "nethelp.h"
7
+#include "udp.h"
8
+
9
+/// tick procedure - call every 200ms
10
+void udp_tick200(void)
11
+{
12
+  // TODO
13
+}
14
+
15
+/**
16
+ * @brief process a received UDP packet
17
+ * @param[in] ptr pointer to data of packet
18
+ * @param[in] sz size of packet
19
+ */
20
+void udp_recv(void *ptr, unsigned int sz)
21
+{
22
+  // TODO
23
+  (void)ptr;
24
+  (void)sz;
25
+}
26
+
27
+/**
28
+ * @brief send a UDP packet
29
+ * @param[in] ptr pointer to data of packet
30
+ * @param[in] sz size of packet
31
+ *
32
+ * ptr must point to a udp_packet of sufficient size (ethernet padding)
33
+ * with ip_hdr.proto and udp_hdr.src_port, udp_hdr.dest_port, ip_hdr.dest
34
+ * already initialized
35
+ */
36
+void udp_send(void *ptr, unsigned int sz)
37
+{
38
+  // TODO
39
+  (void)ptr;
40
+  (void)sz;
41
+}
42
+
... ...
@@ -0,0 +1,49 @@
1
+#ifndef UDP_H
2
+#define UDP_H
3
+
4
+#include "ethernet.h"
5
+#include "ip.h"
6
+
7
+/// header of UDP packet
8
+struct udp_header
9
+{
10
+  unsigned short src_port;
11
+  unsigned short dest_port;
12
+  unsigned short length;
13
+  unsigned short chk;
14
+} __attribute__((packed));
15
+
16
+/// UDP packet
17
+struct udp_packet
18
+{
19
+  struct ethernet_header eth_hdr;
20
+  struct ip_header ip_hdr;
21
+  struct udp_header udp_hdr;
22
+} __attribute__((packed));
23
+
24
+/// UDP packet with padding
25
+ETHERNET_PAD(udp_packet);
26
+
27
+/// tick procedure - call every 200ms
28
+void udp_tick200(void);
29
+
30
+/**
31
+ * @brief process a received UDP packet
32
+ * @param[in] ptr pointer to data of packet
33
+ * @param[in] sz size of packet
34
+ */
35
+void udp_recv(void *ptr, unsigned int sz);
36
+
37
+/**
38
+ * @brief send a UDP packet
39
+ * @param[in] ptr pointer to data of packet
40
+ * @param[in] sz size of packet
41
+ *
42
+ * ptr must point to a udp_packet of sufficient size (ethernet padding)
43
+ * with ip_hdr.proto and udp_hdr.src_port, udp_hdr.dest_port, ip_hdr.dest
44
+ * already initialized
45
+ */
46
+void udp_send(void *ptr, unsigned int sz);
47
+
48
+#endif // #ifdef UDP_H
49
+
... ...
@@ -29,22 +29,37 @@ ARCHITECTURE a_testbed OF e_testbed IS
29 29
         );
30 30
     END COMPONENT e_system;
31 31
 
32
-    TYPE t_eth_data IS ARRAY(0 TO 108 - 1) OF std_logic_vector(3 DOWNTO 0);
32
+    -- ICMP echo request
33
+    TYPE t_eth_data IS ARRAY(0 TO 220 - 1) OF std_logic_vector(3 DOWNTO 0);
33 34
     CONSTANT eth_data: t_eth_data := (
34 35
         X"5", X"5", X"5", X"5", X"5", X"5", X"5", X"5",
35 36
         X"5", X"5", X"5", X"5", X"5", X"5", X"5", X"D",
36
-        X"F", X"F", X"F", X"F", X"F", X"F", X"F", X"F",
37
-        X"F", X"F", X"F", X"F", X"2", X"0", X"3", X"0",
38
-        X"4", X"0", X"5", X"0", X"6", X"0", X"7", X"0",
39
-        X"8", X"0", X"6", X"0", X"0", X"0", X"1", X"0",
40
-        X"8", X"0", X"0", X"0", X"6", X"0", X"4", X"0",
41
-        X"0", X"0", X"1", X"0", X"0", X"0", X"d", X"1",
42
-        X"0", X"6", X"c", X"d", X"5", X"7", X"d", X"2",
43
-        X"0", X"c", X"8", X"a", X"0", X"0", X"a", X"0",
44
-        X"f", X"f", X"f", X"f", X"f", X"f", X"f", X"f",
45
-        X"f", X"f", X"f", X"f", X"0", X"c", X"8", X"a",
46
-        X"0", X"0", X"9", X"5", X"0", X"E", X"8", X"0",
47
-        X"8", X"C", X"1", X"B"
37
+        X"2", X"0", X"D", X"4", X"9", X"4", X"0", X"5",
38
+        X"3", X"5", X"1", X"0", X"0", X"0", X"D", X"1",
39
+        X"0", X"6", X"C", X"D", X"5", X"7", X"D", X"2",
40
+        X"8", X"0", X"0", X"0", X"5", X"4", X"0", X"0",
41
+        X"0", X"0", X"4", X"5", X"0", X"0", X"0", X"0",
42
+        X"0", X"4", X"0", X"0", X"0", X"4", X"1", X"0",
43
+        X"8", X"B", X"5", X"F", X"0", X"C", X"8", X"A",
44
+        X"0", X"0", X"A", X"0", X"0", X"C", X"8", X"A",
45
+        X"0", X"0", X"9", X"5", X"8", X"0", X"0", X"0",
46
+        X"E", X"8", X"7", X"5", X"F", X"0", X"2", X"6",
47
+        X"0", X"0", X"1", X"0", X"6", X"E", X"4", X"B",
48
+        X"D", X"6", X"F", X"4", X"0", X"0", X"0", X"0",
49
+        X"0", X"0", X"0", X"0", X"4", X"4", X"E", X"6",
50
+        X"3", X"0", X"0", X"0", X"0", X"0", X"0", X"0",
51
+        X"0", X"0", X"0", X"0", X"0", X"1", X"1", X"1",
52
+        X"2", X"1", X"3", X"1", X"4", X"1", X"5", X"1",
53
+        X"6", X"1", X"7", X"1", X"8", X"1", X"9", X"1",
54
+        X"A", X"1", X"B", X"1", X"C", X"1", X"D", X"1",
55
+        X"E", X"1", X"F", X"1", X"0", X"2", X"1", X"2",
56
+        X"2", X"2", X"3", X"2", X"4", X"2", X"5", X"2",
57
+        X"6", X"2", X"7", X"2", X"8", X"2", X"9", X"2",
58
+        X"A", X"2", X"B", X"2", X"C", X"2", X"D", X"2",
59
+        X"E", X"2", X"F", X"2", X"0", X"3", X"1", X"3",
60
+        X"2", X"3", X"3", X"3", X"4", X"3", X"5", X"3",
61
+        X"6", X"3", X"7", X"3", X"2", X"9", X"1", X"C",
62
+        X"0", X"1", X"2", X"C"
48 63
         );
49 64
 
50 65
     SIGNAL s_clk:           std_logic;
51 66