Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / netlib / ipv4.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13
14 /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
15
16 #include <ipv4.h>
17 #include <udp.h>
18 #include <tcp.h>
19 #include <ethernet.h>
20 #include <time.h>
21 #include <sys/socket.h>
22 #include <string.h>
23
24 /* ARP Message types */
25 #define ARP_REQUEST            1
26 #define ARP_REPLY              2
27
28 /* ARP talbe size (+1) */
29 #define ARP_ENTRIES 10
30
31 /* ICMP Message types */
32 #define ICMP_ECHO_REPLY            0
33 #define ICMP_DST_UNREACHABLE       3
34 #define ICMP_SRC_QUENCH            4
35 #define ICMP_REDIRECT              5
36 #define ICMP_ECHO_REQUEST          8
37 #define ICMP_TIME_EXCEEDED        11
38 #define ICMP_PARAMETER_PROBLEM    12
39 #define ICMP_TIMESTAMP_REQUEST    13
40 #define ICMP_TIMESTAMP_REPLY      14
41 #define ICMP_INFORMATION_REQUEST  15
42 #define ICMP_INFORMATION_REPLY    16
43
44 /** \struct arp_entry
45  *  A entry that describes a mapping between IPv4- and MAC-address.
46  */
47 typedef struct arp_entry arp_entry_t;
48 struct arp_entry {
49         uint32_t ipv4_addr;
50         uint8_t  mac_addr[6];
51         uint8_t  eth_frame[ETH_MTU_SIZE];
52         int      eth_len;
53         int      pkt_pending;
54 };
55
56 /** \struct icmphdr
57  *  ICMP packet
58  */
59 struct icmphdr {
60         unsigned char type;
61         unsigned char code;
62         unsigned short int checksum;
63         union {
64                 /* for type 3 "Destination Unreachable" */
65                 unsigned int unused;
66                 /* for type 0 and 8 */
67                 struct echo {
68                         unsigned short int id;
69                         unsigned short int seq;
70                 } echo;
71         } options;
72         union {
73                 /* payload for destination unreachable */
74                 struct dun {
75                         unsigned char iphdr[20];
76                         unsigned char data[64];
77                 } dun;
78                 /* payload for echo or echo reply */
79                 /* maximum size supported is 84 */
80                 unsigned char data[84];
81         } payload;
82 };
83
84 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
85
86 static unsigned short
87 checksum(unsigned short *packet, int words);
88
89 static void
90 arp_send_request(int fd, uint32_t dest_ip);
91
92 static void
93 arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac);
94
95 static void
96 fill_arphdr(uint8_t * packet, uint8_t opcode,
97             const uint8_t * src_mac, uint32_t src_ip,
98             const uint8_t * dest_mac, uint32_t dest_ip);
99
100 static arp_entry_t*
101 lookup_mac_addr(uint32_t ipv4_addr);
102
103 static void
104 fill_udp_checksum(struct iphdr *ipv4_hdr);
105
106 static int8_t
107 handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize);
108
109 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
110
111 /* Routing parameters */
112 static uint32_t own_ip       = 0;
113 static uint32_t multicast_ip = 0;
114 static uint32_t router_ip    = 0;
115 static uint32_t subnet_mask  = 0;
116
117 /* helper variables */
118 static uint32_t ping_dst_ip;
119 static const uint8_t null_mac_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
120 static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
121 static       uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
122
123 /* There are only (ARP_ENTRIES-1) effective entries because
124  * the entry that is pointed by arp_producer is never used.
125  */
126 static unsigned int arp_consumer = 0;
127 static unsigned int arp_producer = 0;
128 static arp_entry_t  arp_table[ARP_ENTRIES];
129 static arp_entry_t  pending_pkt;
130
131 /* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
132 int   (*send_ip) (int fd, void *, int);
133
134 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
135
136 /**
137  * IPv4: Initialize the environment for the IPv4 layer.
138  */
139 static void
140 ipv4_init(void)
141 {
142         int i;
143
144         ping_dst_ip = 0;
145
146         // clear ARP table
147         arp_consumer = 0;
148         arp_producer = 0;
149         for(i=0; i<ARP_ENTRIES; ++i) {
150                 arp_table[i].ipv4_addr = 0;
151                 memset(arp_table[i].mac_addr, 0, 6);
152                 arp_table[i].eth_len = 0;
153                 arp_table[i].pkt_pending = 0;
154         }
155
156         /* Set IP send function to send_ipv4() */ 
157         send_ip = &send_ipv4;
158 }
159
160 /**
161  * IPv4: Set the own IPv4 address.
162  *
163  * @param  _own_ip  client IPv4 address (e.g. 127.0.0.1)
164  */
165 void
166 set_ipv4_address(uint32_t _own_ip)
167 {
168         own_ip = _own_ip;
169         ipv4_init();
170 }
171
172 /**
173  * IPv4: Get the own IPv4 address.
174  *
175  * @return client IPv4 address (e.g. 127.0.0.1)
176  */
177 uint32_t
178 get_ipv4_address(void)
179 {
180         return own_ip;
181 }
182
183 /**
184  * IPv4: Set the IPv4 multicast address.
185  *
186  * @param  _own_ip  multicast IPv4 address (224.0.0.0 - 239.255.255.255)
187  */
188 void
189 set_ipv4_multicast(uint32_t _multicast_ip)
190 {
191         // is this IP Multicast out of range (224.0.0.0 - 239.255.255.255)
192         if((htonl(_multicast_ip) < 0xE0000000)
193         || (htonl(_multicast_ip) > 0xEFFFFFFF)) {
194                 multicast_ip = 0;
195                 memset(multicast_mac, 0xFF, 6);
196                 return;
197         }
198
199         multicast_ip = _multicast_ip;
200         multicast_mac[0] = 0x01;
201         multicast_mac[1] = 0x00;
202         multicast_mac[2] = 0x5E;
203         multicast_mac[3] = (uint8_t) 0x7F & (multicast_ip >> 16);
204         multicast_mac[4] = (uint8_t) 0xFF & (multicast_ip >>  8);
205         multicast_mac[5] = (uint8_t) 0xFF & (multicast_ip >>  0);
206 }
207
208 /**
209  * IPv4: Get the IPv4 multicast address.
210  *
211  * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set)
212  */
213 uint32_t
214 get_ipv4_multicast(void)
215 {
216         return multicast_ip;
217 }
218
219 /**
220  * IPv4: Set the routers IPv4 address.
221  *
222  * @param  _router_ip   router IPv4 address
223  */
224 void
225 set_ipv4_router(uint32_t _router_ip)
226 {
227         router_ip = _router_ip;
228         ipv4_init();
229 }
230
231 /**
232  * IPv4: Get the routers IPv4 address.
233  *
234  * @return router IPv4 address
235  */
236 uint32_t
237 get_ipv4_router(void)
238 {
239         return router_ip;
240 }
241
242 /**
243  * IPv4: Set the subnet mask.
244  *
245  * @param  _subnet_mask   netmask of the own IPv4 address
246  */
247 void
248 set_ipv4_netmask(uint32_t _subnet_mask)
249 {
250         subnet_mask = _subnet_mask;
251         ipv4_init();
252 }
253
254 /**
255  * IPv4: Get the subnet mask.
256  *
257  * @return netmask of the own IPv4 address
258  */
259 uint32_t
260 get_ipv4_netmask(void)
261 {
262         return subnet_mask;
263 }
264
265 /**
266  * IPv4: Creates IP-packet. Places IP-header in a packet and fills it
267  *       with corresponding information.
268  *       <p>
269  *       Use this function with similar functions for other network layers
270  *       (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr).
271  *
272  * @param  packet      Points to the place where IP-header must be placed.
273  * @param  packetsize  Size of the packet in bytes incl. this hdr and data.
274  * @param  ip_proto    Type of the next level protocol (e.g. UDP).
275  * @param  ip_src      Sender IP address
276  * @param  ip_dst      Receiver IP address
277  * @see                iphdr
278  * @see                fill_ethhdr
279  * @see                fill_udphdr
280  * @see                fill_dnshdr
281  * @see                fill_btphdr
282  */
283 void
284 fill_iphdr(uint8_t * packet, uint16_t packetsize,
285            uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) {
286         struct iphdr * iph = (struct iphdr *) packet;
287
288         iph -> ip_hlv = 0x45;
289         iph -> ip_tos = 0x10;
290         iph -> ip_len = htons(packetsize);
291         iph -> ip_id = htons(0);
292         iph -> ip_off = 0;
293         iph -> ip_ttl = 0xFF;
294         iph -> ip_p = ip_proto;
295         iph -> ip_src = htonl(ip_src);
296         iph -> ip_dst = htonl(ip_dst);
297         iph -> ip_sum = 0;
298 }
299
300 /**
301  * IPv4: Handles IPv4-packets according to Receive-handle diagram.
302  *
303  * @param  fd         socket fd
304  * @param  ip_packet  IP-packet to be handled
305  * @param  packetsize Length of the packet
306  * @return            ZERO - packet handled successfully;
307  *                    NON ZERO - packet was not handled (e.g. bad format)
308  * @see               receive_ether
309  * @see               iphdr
310  */
311 int8_t
312 handle_ipv4(int fd, uint8_t * ip_packet, int32_t packetsize)
313 {
314         struct iphdr * iph;
315         int32_t old_sum;
316         static uint8_t ip_heap[65536 + ETH_MTU_SIZE];
317
318         if (packetsize < sizeof(struct iphdr))
319                 return -1; // packet is too small
320
321         iph = (struct iphdr * ) ip_packet;
322
323         /* Drop it if destination IPv4 address is no IPv4 Broadcast, no
324          * registered IPv4 Multicast and not our Unicast address
325          */
326         if((multicast_ip == 0 && iph->ip_dst >= 0xE0000000 && iph->ip_dst <= 0xEFFFFFFF)
327         || (multicast_ip != iph->ip_dst && iph->ip_dst != 0xFFFFFFFF &&
328             own_ip != 0 && iph->ip_dst != own_ip)) {
329                 return -1;
330         }
331
332         old_sum = iph -> ip_sum;
333         iph -> ip_sum = 0;
334         if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1))
335                 return -1; // Wrong IP checksum
336
337         // is it the first fragment in a packet?
338         if (((iph -> ip_off) & 0x1FFF) == 0) {
339                 // is it part of more fragments?
340                 if (((iph -> ip_off) & 0x2000) == 0x2000) {
341                         memcpy(ip_heap, ip_packet, iph->ip_len);
342                         return 0;
343                 }
344         }
345         // it's not the first fragment
346         else {
347                 // get the first fragment
348                 struct iphdr * iph_first = (struct iphdr * ) ip_heap;
349
350                 // is this fragment not part of the first one, then exit
351                 if ((iph_first->ip_id  != iph->ip_id ) ||
352                     (iph_first->ip_p   != iph->ip_p  ) ||
353                     (iph_first->ip_src != iph->ip_src) ||
354                     (iph_first->ip_dst != iph->ip_dst)) {
355                         return 0;
356                 }
357
358                 // this fragment is part of the first one!
359                 memcpy(ip_heap + sizeof(struct iphdr) +
360                        ((iph -> ip_off) & 0x1FFF) * 8,
361                        ip_packet + sizeof(struct iphdr),
362                        iph -> ip_len - sizeof(struct iphdr));
363
364                 // is it part of more fragments? Then return.
365                 if (((iph -> ip_off) & 0x2000) == 0x2000) {
366                         return 0;
367                 }
368
369                 // packet is completly reassambled now!
370
371                 // recalculate ip_len and set iph and ip_packet to the
372                 iph_first->ip_len = iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8;
373
374                 // set iph and ip_packet to the resulting packet.
375                 ip_packet = ip_heap;
376                 iph = (struct iphdr * ) ip_packet;
377         }
378
379         switch (iph -> ip_p) {
380         case IPTYPE_ICMP:
381                 return handle_icmp(fd, iph, ip_packet + sizeof(struct iphdr),
382                                    iph -> ip_len - sizeof(struct iphdr));
383         case IPTYPE_UDP:
384                 return handle_udp(fd, ip_packet + sizeof(struct iphdr),
385                                   iph -> ip_len - sizeof(struct iphdr));
386         case IPTYPE_TCP:
387                 return handle_tcp(ip_packet + sizeof(struct iphdr),
388                                   iph -> ip_len - sizeof(struct iphdr));
389         default:
390                 break;
391         }
392         return -1; // Unknown protocol
393 }
394
395 /**
396  * IPv4: Send IPv4-packets.
397  *
398  *       Before the packet is sent there are some patcches performed:
399  *       - IPv4 source address is replaced by our unicast IPV4 address
400  *         if it is set to 0 or 1
401  *       - IPv4 destination address is replaced by our multicast IPV4 address
402  *         if it is set to 1
403  *       - IPv4 checksum is calculaded.
404  *       - If payload type is UDP, then the UDP checksum is calculated also.
405  *
406  *       We send an ARP request first, if this is the first packet sent to
407  *       the declared IPv4 destination address. In this case we store the
408  *       the packet and send it later if we receive the ARP response.
409  *       If the MAC address is known already, then we send the packet immediately.
410  *       If there is already an ARP request pending, then we drop this packet
411  *       and send again an ARP request.
412  *
413  * @param  fd         socket fd
414  * @param  ip_packet  IP-packet to be handled
415  * @param  packetsize Length of the packet
416  * @return            -2 - packet dropped (MAC address not resolved - ARP request pending)
417  *                    -1 - packet dropped (bad format)
418  *                     0 - packet stored  (ARP request sent - packet will be sent if
419  *                                         ARP response is received)
420  *                    >0 - packet send    (number of transmitted bytes is returned)
421  *
422  * @see               receive_ether
423  * @see               iphdr
424  */
425 int
426 send_ipv4(int fd, void* buffer, int len)
427 {
428         arp_entry_t *arp_entry = 0;
429         struct iphdr *ip;
430         const uint8_t *mac_addr = 0;
431         uint32_t ip_dst = 0;
432
433         if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE)
434                 return -1;
435
436         ip = (struct iphdr  *) buffer;
437
438         /* Replace source IPv4 address with our own unicast IPv4 address
439          * if it's 0 (= own unicast source address not specified).
440          */
441         if(ip->ip_src == 0) {
442                 ip->ip_src = htonl( own_ip );
443         }
444         /* Replace source IPv4 address with our unicast IPv4 address and
445          * replace destination IPv4 address with our multicast IPv4 address
446          * if source address is set to 1.
447          */
448         else if(ip->ip_src == 1) {
449                 ip->ip_src = htonl( own_ip );
450                 ip->ip_dst = htonl( multicast_ip );
451         }
452
453         // Calculate the IPv4 checksum
454         ip->ip_sum = 0;
455         ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1);
456
457         // if payload type is UDP, then we need to calculate the
458         // UDP checksum that depends on the IP header
459         if(ip->ip_p == IPTYPE_UDP) {
460                 fill_udp_checksum(ip);
461         }
462
463         ip_dst = ip->ip_dst;
464         // Check if the MAC address is already cached
465         if(~ip->ip_dst == 0
466         || ( ((~subnet_mask) & ip->ip_dst) == ~subnet_mask &&
467              (  subnet_mask  & ip->ip_dst) == (subnet_mask & own_ip)))  {
468                 arp_entry = &arp_table[arp_producer];
469                 mac_addr = broadcast_mac;
470         }
471         else if(ip->ip_dst == multicast_ip) {
472                 arp_entry = &arp_table[arp_producer];
473                 mac_addr = multicast_mac;
474         }
475         else {
476                 // Check if IP address is in the same subnet as we are
477                 if((subnet_mask & own_ip) == (subnet_mask & ip->ip_dst))
478                         arp_entry = lookup_mac_addr(ip->ip_dst);
479                 // if not then we need to know the router's IP address
480                 else {
481                         ip_dst = router_ip;
482                         arp_entry = lookup_mac_addr(router_ip);
483                 }
484                 if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0)
485                         mac_addr = arp_entry->mac_addr;
486         }
487
488         // If we could not resolv the MAC address by our own...
489         if(!mac_addr) {
490                 // send the ARP request
491                 arp_send_request(fd, ip_dst);
492
493                 // drop the current packet if there is already a ARP request pending
494                 if(arp_entry)
495                         return -2;
496
497                 // take the next entry in the ARP table to prepare a the new ARP entry.
498                 arp_entry = &arp_table[arp_producer];
499                 arp_producer = (arp_producer+1)%ARP_ENTRIES;
500
501                 // if ARP table is full then we must drop the oldes entry.
502                 if(arp_consumer == arp_producer)
503                         arp_consumer = (arp_consumer+1)%ARP_ENTRIES;
504
505                 // store the packet to be send if the ARP reply is received
506                 arp_entry->pkt_pending = 1;
507                 arp_entry->ipv4_addr = ip_dst;
508                 memset(arp_entry->mac_addr, 0, 6);
509                 pending_pkt.ipv4_addr = ip_dst;
510                 memset(pending_pkt.mac_addr, 0, 6);
511                 fill_ethhdr (pending_pkt.eth_frame, htons(ETHERTYPE_IP),
512                              get_mac_address(), null_mac_addr);
513                 memcpy(&pending_pkt.eth_frame[sizeof(struct ethhdr)],
514                        buffer, len);
515                 pending_pkt.eth_len = len + sizeof(struct ethhdr);
516
517                 set_timer(TICKS_SEC);
518                 do {
519                         receive_ether(fd);
520                         if (!arp_entry->eth_len)
521                                 break;
522                 } while (get_timer() > 0);
523
524                 return 0;
525         }
526
527         // Send the packet with the known MAC address
528         fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP),
529                     get_mac_address(), mac_addr);
530         memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len);
531         return send_ether(fd, arp_entry->eth_frame, len + sizeof(struct ethhdr));
532 }
533
534 /**
535  * IPv4: Calculate UDP checksum. Places the result into the UDP-header.
536  *      <p>
537  *      Use this function after filling the UDP payload.
538  *
539  * @param  ipv4_hdr    Points to the place where IPv4-header starts.
540  */
541
542 static void
543 fill_udp_checksum(struct iphdr *ipv4_hdr)
544 {
545         int i;
546         unsigned long checksum = 0;
547         struct iphdr ip_hdr;
548         char *ptr;
549         udp_hdr_t *udp_hdr;
550
551         udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1);
552         udp_hdr->uh_sum = 0;
553
554         memset(&ip_hdr, 0, sizeof(struct iphdr));
555         ip_hdr.ip_src    = ipv4_hdr->ip_src;
556         ip_hdr.ip_dst    = ipv4_hdr->ip_dst;
557         ip_hdr.ip_len    = udp_hdr->uh_ulen;
558         ip_hdr.ip_p      = ipv4_hdr->ip_p;
559
560         ptr = (char*) udp_hdr;
561         for (i = 0; i < udp_hdr->uh_ulen; i+=2)
562                 checksum += *((uint16_t*) &ptr[i]);
563
564         ptr = (char*) &ip_hdr;
565         for (i = 0; i < sizeof(struct iphdr); i+=2)
566                 checksum += *((uint16_t*) &ptr[i]);
567
568         checksum = (checksum >> 16) + (checksum & 0xffff);
569         checksum += (checksum >> 16);
570         udp_hdr->uh_sum = ~checksum;
571
572         /* As per RFC 768, if the computed  checksum  is zero,
573          * it is transmitted as all ones (the equivalent in
574          * one's complement arithmetic).
575          */
576         if (udp_hdr->uh_sum == 0)
577                 udp_hdr->uh_sum = ~udp_hdr->uh_sum;
578 }
579
580 /**
581  * IPv4: Calculates checksum for IP header.
582  *
583  * @param  packet     Points to the IP-header
584  * @param  words      Size of the packet in words incl. IP-header and data.
585  * @return            Checksum
586  * @see               iphdr
587  */
588 static unsigned short
589 checksum(unsigned short * packet, int words)
590 {
591         unsigned long checksum;
592
593         for (checksum = 0; words > 0; words--)
594                 checksum += *packet++;
595         checksum = (checksum >> 16) + (checksum & 0xffff);
596         checksum += (checksum >> 16);
597
598         return ~checksum;
599 }
600
601 static arp_entry_t*
602 lookup_mac_addr(uint32_t ipv4_addr)
603 {
604         unsigned int i;
605
606         for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
607                 if(arp_table[i].ipv4_addr == ipv4_addr)
608                         return &arp_table[i];
609         }
610         return 0;
611 }
612
613
614 /**
615  * ARP: Sends an ARP-request package.
616  *      For given IPv4 retrieves MAC via ARP (makes several attempts)
617  *
618  * @param  fd        socket fd
619  * @param  dest_ip   IP of the host which MAC should be obtained
620  */
621 static void
622 arp_send_request(int fd, uint32_t dest_ip)
623 {
624         arp_entry_t *arp_entry = &arp_table[arp_producer];
625
626         memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
627         fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST,
628                     get_mac_address(), own_ip, broadcast_mac, dest_ip);
629         fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
630                     get_mac_address(), broadcast_mac);
631
632         send_ether(fd, arp_entry->eth_frame,
633              sizeof(struct ethhdr) + sizeof(struct arphdr));
634 }
635
636 /**
637  * ARP: Sends an ARP-reply package.
638  *      This package is used to serve foreign requests (in case IP in
639  *      foreign request matches our host IP).
640  *
641  * @param  fd        socket fd
642  * @param  src_ip    requester IP address (foreign IP)
643  * @param  src_mac   requester MAC address (foreign MAC)
644  */
645 static void
646 arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac)
647 {
648         arp_entry_t *arp_entry = &arp_table[arp_producer];
649
650         memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
651         fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
652                     get_mac_address(), src_mac);
653         fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY,
654                     get_mac_address(), own_ip, src_mac, src_ip);
655
656         send_ether(fd, arp_entry->eth_frame,
657              sizeof(struct ethhdr) + sizeof(struct arphdr));
658 }
659
660 /**
661  * ARP: Creates ARP package. Places ARP-header in a packet and fills it
662  *      with corresponding information.
663  *      <p>
664  *      Use this function with similar functions for other network layers
665  *      (fill_ethhdr).
666  *
667  * @param  packet      Points to the place where ARP-header must be placed.
668  * @param  opcode      Identifies is it request (ARP_REQUEST)
669  *                     or reply (ARP_REPLY) package.
670  * @param  src_mac     sender MAC address
671  * @param  src_ip      sender IP address
672  * @param  dest_mac    receiver MAC address
673  * @param  dest_ip     receiver IP address
674  * @see                arphdr
675  * @see                fill_ethhdr
676  */
677 static void
678 fill_arphdr(uint8_t * packet, uint8_t opcode,
679             const uint8_t * src_mac, uint32_t src_ip,
680             const uint8_t * dest_mac, uint32_t dest_ip)
681 {
682         struct arphdr * arph = (struct arphdr *) packet;
683
684         arph -> hw_type = htons(1);
685         arph -> proto_type = htons(ETHERTYPE_IP);
686         arph -> hw_len = 6;
687         arph -> proto_len = 4;
688         arph -> opcode = htons(opcode);
689
690         memcpy(arph->src_mac, src_mac, 6);
691         arph->src_ip = htonl(src_ip);
692         memcpy(arph->dest_mac, dest_mac, 6);
693         arph->dest_ip = htonl(dest_ip);
694 }
695
696 /**
697  * ARP: Handles ARP-messages according to Receive-handle diagram.
698  *      Updates arp_table for outstanding ARP requests (see arp_getmac).
699  *
700  * @param  fd         socket fd
701  * @param  packet     ARP-packet to be handled
702  * @param  packetsize length of the packet
703  * @return            ZERO - packet handled successfully;
704  *                    NON ZERO - packet was not handled (e.g. bad format)
705  * @see               arp_getmac
706  * @see               receive_ether
707  * @see               arphdr
708  */
709 int8_t
710 handle_arp(int fd, uint8_t * packet, int32_t packetsize)
711 {
712         struct arphdr * arph = (struct arphdr *) packet;
713
714         if (packetsize < sizeof(struct arphdr))
715                 return -1; // Packet is too small
716
717         if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP))
718                 return -1; // Unknown hardware or unsupported protocol
719
720         if (arph -> dest_ip != htonl(own_ip))
721                 return -1; // receiver IP doesn't match our IP
722
723         switch(htons(arph -> opcode)) {
724         case ARP_REQUEST:
725                 // foreign request
726                 if(own_ip != 0)
727                         arp_send_reply(fd, htonl(arph->src_ip), arph -> src_mac);
728                 return 0; // no error
729         case ARP_REPLY: {
730                 unsigned int i;
731                 // if it is not for us -> return immediately
732                 if(memcmp(get_mac_address(), arph->dest_mac, 6)) {
733                         return 0; // no error
734                 }
735
736                 if(arph->src_ip == 0) {
737                         // we are not interested for a MAC address if
738                         // the IPv4 address is 0.0.0.0 or ff.ff.ff.ff
739                         return -1;
740                 }
741
742                 // now let's find the corresponding entry in the ARP table
743
744                 for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
745                         if(arp_table[i].ipv4_addr == arph->src_ip)
746                                 break;
747                 }
748                 if(i == arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr, 6) != 0) {
749                         // we have not asked to resolve this IPv4 address !
750                         return -1;
751                 }
752
753                 memcpy(arp_table[i].mac_addr, arph->src_mac, 6);
754
755                 // do we have something to send
756                 if (arp_table[i].pkt_pending) {
757                         struct ethhdr * ethh = (struct ethhdr *) pending_pkt.eth_frame;
758                         memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6);
759
760                         send_ether(fd, pending_pkt.eth_frame, pending_pkt.eth_len);
761                         pending_pkt.pkt_pending = 0;
762                         arp_table[i].eth_len = 0;
763                 }
764                 return 0; // no error
765         }
766         default:
767                 break;
768         }
769         return -1; // Invalid message type
770 }
771
772 /**
773  * ICMP: Send an ICMP Echo request to destination IPv4 address.
774  *       This function does also set a global variable to the
775  *       destination IPv4 address. If there is an ICMP Echo Reply
776  *       received later then the variable is set back to 0.
777  *       In other words, reading a value of 0 form this variable
778  *       means that an answer to the request has been arrived.
779  *
780  * @param  fd            socket descriptor
781  * @param  _ping_dst_ip  destination IPv4 address
782  */
783 void
784 ping_ipv4(int fd, uint32_t _ping_dst_ip)
785 {
786         unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)];
787         struct icmphdr *icmp;
788
789         ping_dst_ip = _ping_dst_ip;
790
791         if(ping_dst_ip == 0)
792                 return;
793
794         fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP,
795                    0, ping_dst_ip);
796         icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));
797         icmp->type = ICMP_ECHO_REQUEST;
798         icmp->code = 0;
799         icmp->checksum = 0;
800         icmp->options.echo.id = 0xd476;
801         icmp->options.echo.seq = 1;
802
803         memset(icmp->payload.data, '*', sizeof(icmp->payload.data));
804
805         icmp->checksum =
806             checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1);
807         send_ipv4(fd, packet, sizeof(struct iphdr) + sizeof(struct icmphdr));
808 }
809
810 /**
811  * ICMP: Return host IPv4 address that we are waiting for a
812  *       ICMP Echo reply message. If this value is 0 then we have
813  *       received an reply.
814  *
815  * @return  ping_dst_ip  host IPv4 address
816  */
817 uint32_t
818 pong_ipv4(void)
819 {
820         return ping_dst_ip;
821 }
822
823 /**
824  * ICMP: Handles ICMP-packets according to Receive-handle diagram.
825  *
826  * @param  fd         socket fd
827  * @param  icmp_packet  ICMP-packet to be handled
828  * @param  packetsize   Length of the packet
829  * @return              ZERO - packet handled successfully;
830  *                      NON ZERO - packet was not handled (e.g. bad format)
831  * @see                 handle_ipv4
832  */
833 static int8_t
834 handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize)
835 {
836         struct icmphdr *icmp = (struct icmphdr *) packet;
837
838         switch(icmp->type) {
839         case ICMP_ECHO_REPLY:
840                 if (icmp->options.echo.id != 0xd476)
841                         return -1;
842                 if (icmp->options.echo.seq != 1)
843                         return -1;
844                 if(ping_dst_ip != iph->ip_src
845                 || ping_dst_ip == 0)
846                         return -1;
847                 ping_dst_ip = 0;
848                 break;
849         case ICMP_DST_UNREACHABLE: {
850                 // We've got Destination Unreachable msg
851                 // Inform corresponding upper network layers
852                 struct iphdr * bad_iph = (struct iphdr * ) &icmp->payload;
853
854                 switch(bad_iph->ip_p) {
855                 case IPTYPE_TCP:
856                         handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize
857                                        - sizeof(struct icmphdr)
858                                        - sizeof(struct iphdr), icmp->code);
859                         break;
860                 case IPTYPE_UDP:
861                         handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize
862                                        - sizeof(struct icmphdr)
863                                        - sizeof(struct iphdr), icmp->code);
864                         break;
865                 }
866                 break;
867         }
868         case ICMP_SRC_QUENCH:
869                 break;
870         case ICMP_REDIRECT:
871                 break;
872         case ICMP_ECHO_REQUEST: {
873                 // We've got an Echo Request - answer with Echo Replay msg
874                 unsigned char reply_packet[sizeof(struct iphdr) + packetsize];
875                 struct icmphdr *reply_icmph;
876
877                 fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize,
878                            IPTYPE_ICMP, 0, iph->ip_src);
879
880                 reply_icmph = (struct icmphdr *) &reply_packet[sizeof(struct iphdr)];
881                 memcpy(reply_icmph, packet, packetsize);
882                 reply_icmph -> type = ICMP_ECHO_REPLY;
883                 reply_icmph -> checksum = 0;
884                 reply_icmph->checksum = checksum((unsigned short *) reply_icmph,
885                                                  sizeof(struct icmphdr) >> 1);
886
887                 send_ipv4(fd, reply_packet, sizeof(struct iphdr) + packetsize);
888                 break;
889         }
890         case ICMP_TIME_EXCEEDED:
891                 break;
892         case ICMP_PARAMETER_PROBLEM:
893                 break;
894         case ICMP_TIMESTAMP_REQUEST:
895                 break;
896         case ICMP_TIMESTAMP_REPLY:
897                 break;
898         case ICMP_INFORMATION_REQUEST:
899                 break;
900         case ICMP_INFORMATION_REPLY:
901                 break;
902         }
903         return 0;
904 }