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