1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
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
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
14 /********************** DEFINITIONS & DECLARATIONS ***********************/
21 #include <sys/socket.h>
24 /* ARP Message types */
28 /* ARP talbe size (+1) */
29 #define ARP_ENTRIES 10
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
45 * A entry that describes a mapping between IPv4- and MAC-address.
47 typedef struct arp_entry arp_entry_t;
51 uint8_t eth_frame[ETH_MTU_SIZE];
62 unsigned short int checksum;
64 /* for type 3 "Destination Unreachable" */
66 /* for type 0 and 8 */
68 unsigned short int id;
69 unsigned short int seq;
73 /* payload for destination unreachable */
75 unsigned char iphdr[20];
76 unsigned char data[64];
78 /* payload for echo or echo reply */
79 /* maximum size supported is 84 */
80 unsigned char data[84];
84 /****************************** PROTOTYPES *******************************/
86 static unsigned short checksum(unsigned short *packet, int words);
88 static void arp_send_request(int fd, uint32_t dest_ip);
90 static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac);
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);
96 static arp_entry_t *lookup_mac_addr(uint32_t ipv4_addr);
98 static void fill_udp_checksum(struct iphdr *ipv4_hdr);
100 static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet,
103 /****************************** LOCAL VARIABLES **************************/
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;
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};
117 /* There are only (ARP_ENTRIES-1) effective entries because
118 * the entry that is pointed by arp_producer is never used.
120 static unsigned int arp_consumer = 0;
121 static unsigned int arp_producer = 0;
122 static arp_entry_t arp_table[ARP_ENTRIES];
124 static uint8_t pending_pkt_frame[ETH_MTU_SIZE];
125 static int pending_pkt_len;
127 /* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
128 int (*send_ip) (int fd, void *, int);
130 /***************************** IMPLEMENTATION ****************************/
133 * IPv4: Initialize the environment for the IPv4 layer.
135 static void ipv4_init(void)
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;
151 /* Set IP send function to send_ipv4() */
152 send_ip = &send_ipv4;
156 * IPv4: Set the own IPv4 address.
158 * @param _own_ip client IPv4 address (e.g. 127.0.0.1)
160 void set_ipv4_address(uint32_t _own_ip)
167 * IPv4: Get the own IPv4 address.
169 * @return client IPv4 address (e.g. 127.0.0.1)
171 uint32_t get_ipv4_address(void)
177 * IPv4: Set the IPv4 multicast address.
179 * @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255)
181 void set_ipv4_multicast(uint32_t _multicast_ip)
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)) {
187 memset(multicast_mac, 0xFF, 6);
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);
201 * IPv4: Get the IPv4 multicast address.
203 * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set)
205 uint32_t get_ipv4_multicast(void)
211 * IPv4: Set the routers IPv4 address.
213 * @param _router_ip router IPv4 address
215 void set_ipv4_router(uint32_t _router_ip)
217 router_ip = _router_ip;
222 * IPv4: Get the routers IPv4 address.
224 * @return router IPv4 address
226 uint32_t get_ipv4_router(void)
232 * IPv4: Set the subnet mask.
234 * @param _subnet_mask netmask of the own IPv4 address
236 void set_ipv4_netmask(uint32_t _subnet_mask)
238 subnet_mask = _subnet_mask;
243 * IPv4: Get the subnet mask.
245 * @return netmask of the own IPv4 address
247 uint32_t get_ipv4_netmask(void)
253 * IPv4: Creates IP-packet. Places IP-header in a packet and fills it
254 * with corresponding information.
256 * Use this function with similar functions for other network layers
257 * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr).
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
270 void fill_iphdr(uint8_t * packet, uint16_t packetsize,
271 uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst)
273 struct iphdr * iph = (struct iphdr *) packet;
275 iph -> ip_hlv = 0x45;
276 iph -> ip_tos = 0x10;
277 iph -> ip_len = htons(packetsize);
278 iph -> ip_id = htons(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);
288 * IPv4: Handles IPv4-packets according to Receive-handle diagram.
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)
298 int8_t handle_ipv4(int fd, uint8_t * ip_packet, uint32_t packetsize)
302 static uint8_t ip_heap[65536 + ETH_MTU_SIZE];
304 if (packetsize < sizeof(struct iphdr))
305 return -1; // packet is too small
307 iph = (struct iphdr * ) ip_packet;
309 /* Drop it if destination IPv4 address is no IPv4 Broadcast, no
310 * registered IPv4 Multicast and not our Unicast address
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)) {
318 old_sum = iph -> ip_sum;
320 if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1))
321 return -1; // Wrong IP checksum
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);
331 // it's not the first fragment
333 // get the first fragment
334 struct iphdr * iph_first = (struct iphdr * ) ip_heap;
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)) {
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));
350 // is it part of more fragments? Then return.
351 if (((iph -> ip_off) & 0x2000) == 0x2000) {
355 // packet is completly reassambled now!
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;
360 // set iph and ip_packet to the resulting packet.
362 iph = (struct iphdr * ) ip_packet;
365 switch (iph -> ip_p) {
367 return handle_icmp(fd, iph, ip_packet + sizeof(struct iphdr),
368 iph -> ip_len - sizeof(struct iphdr));
370 return handle_udp(fd, ip_packet + sizeof(struct iphdr),
371 iph -> ip_len - sizeof(struct iphdr));
373 return handle_tcp(ip_packet + sizeof(struct iphdr),
374 iph -> ip_len - sizeof(struct iphdr));
378 return -1; // Unknown protocol
382 * IPv4: Send IPv4-packets.
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
389 * - IPv4 checksum is calculaded.
390 * - If payload type is UDP, then the UDP checksum is calculated also.
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.
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)
411 int send_ipv4(int fd, void* buffer, int len)
413 arp_entry_t *arp_entry = 0;
415 const uint8_t *mac_addr = 0;
418 if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE)
421 ip = (struct iphdr *) buffer;
423 /* Replace source IPv4 address with our own unicast IPv4 address
424 * if it's 0 (= own unicast source address not specified).
426 if(ip->ip_src == 0) {
427 ip->ip_src = htonl( own_ip );
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.
433 else if(ip->ip_src == 1) {
434 ip->ip_src = htonl( own_ip );
435 ip->ip_dst = htonl( multicast_ip );
438 // Calculate the IPv4 checksum
440 ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1);
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);
449 // Check if the MAC address is already cached
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;
456 else if(ip->ip_dst == multicast_ip) {
457 arp_entry = &arp_table[arp_producer];
458 mac_addr = multicast_mac;
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
467 arp_entry = lookup_mac_addr(router_ip);
469 if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0)
470 mac_addr = arp_entry->mac_addr;
473 // If we could not resolv the MAC address by our own...
475 // send the ARP request
476 arp_send_request(fd, ip_dst);
478 // drop the current packet if there is already a ARP request pending
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;
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;
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)],
498 pending_pkt_len = len + sizeof(struct ethhdr);
500 set_timer(TICKS_SEC);
503 if (!arp_entry->eth_len)
505 } while (get_timer() > 0);
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));
518 * IPv4: Calculate UDP checksum. Places the result into the UDP-header.
520 * Use this function after filling the UDP payload.
522 * @param ipv4_hdr Points to the place where IPv4-header starts.
524 static void fill_udp_checksum(struct iphdr *ipv4_hdr)
527 unsigned long checksum = 0;
532 udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1);
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;
541 ptr = (char*) udp_hdr;
542 for (i = 0; i < udp_hdr->uh_ulen; i+=2)
543 checksum += *((uint16_t*) &ptr[i]);
545 ptr = (char*) &ip_hdr;
546 for (i = 0; i < sizeof(struct iphdr); i+=2)
547 checksum += *((uint16_t*) &ptr[i]);
549 checksum = (checksum >> 16) + (checksum & 0xffff);
550 checksum += (checksum >> 16);
551 udp_hdr->uh_sum = ~checksum;
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).
557 if (udp_hdr->uh_sum == 0)
558 udp_hdr->uh_sum = ~udp_hdr->uh_sum;
562 * IPv4: Calculates checksum for IP header.
564 * @param packet Points to the IP-header
565 * @param words Size of the packet in words incl. IP-header and data.
569 static unsigned short checksum(unsigned short * packet, int words)
571 unsigned long checksum;
573 for (checksum = 0; words > 0; words--)
574 checksum += *packet++;
575 checksum = (checksum >> 16) + (checksum & 0xffff);
576 checksum += (checksum >> 16);
581 static arp_entry_t* lookup_mac_addr(uint32_t ipv4_addr)
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];
594 * ARP: Sends an ARP-request package.
595 * For given IPv4 retrieves MAC via ARP (makes several attempts)
597 * @param fd socket fd
598 * @param dest_ip IP of the host which MAC should be obtained
600 static void arp_send_request(int fd, uint32_t dest_ip)
602 arp_entry_t *arp_entry = &arp_table[arp_producer];
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);
610 send_ether(fd, arp_entry->eth_frame,
611 sizeof(struct ethhdr) + sizeof(struct arphdr));
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).
619 * @param fd socket fd
620 * @param src_ip requester IP address (foreign IP)
621 * @param src_mac requester MAC address (foreign MAC)
623 static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac)
625 arp_entry_t *arp_entry = &arp_table[arp_producer];
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);
633 send_ether(fd, arp_entry->eth_frame,
634 sizeof(struct ethhdr) + sizeof(struct arphdr));
638 * ARP: Creates ARP package. Places ARP-header in a packet and fills it
639 * with corresponding information.
641 * Use this function with similar functions for other network layers
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
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)
658 struct arphdr * arph = (struct arphdr *) packet;
660 arph -> hw_type = htons(1);
661 arph -> proto_type = htons(ETHERTYPE_IP);
663 arph -> proto_len = 4;
664 arph -> opcode = htons(opcode);
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);
673 * ARP: Handles ARP-messages according to Receive-handle diagram.
674 * Updates arp_table for outstanding ARP requests (see arp_getmac).
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)
685 int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize)
687 struct arphdr * arph = (struct arphdr *) packet;
689 if (packetsize < sizeof(struct arphdr))
690 return -1; // Packet is too small
692 if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP))
693 return -1; // Unknown hardware or unsupported protocol
695 if (arph -> dest_ip != htonl(own_ip))
696 return -1; // receiver IP doesn't match our IP
698 switch(htons(arph -> opcode)) {
702 arp_send_reply(fd, htonl(arph->src_ip), arph -> src_mac);
703 return 0; // no error
706 // if it is not for us -> return immediately
707 if(memcmp(get_mac_address(), arph->dest_mac, 6)) {
708 return 0; // no error
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
717 // now let's find the corresponding entry in the ARP table
719 for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
720 if(arp_table[i].ipv4_addr == arph->src_ip)
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 !
728 memcpy(arp_table[i].mac_addr, arph->src_mac, 6);
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);
735 send_ether(fd, pending_pkt_frame, pending_pkt_len);
736 arp_table[i].pkt_pending = 0;
737 arp_table[i].eth_len = 0;
739 return 0; // no error
744 return -1; // Invalid message type
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.
755 * @param fd socket descriptor
756 * @param _ping_dst_ip destination IPv4 address
758 void ping_ipv4(int fd, uint32_t _ping_dst_ip)
760 unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)];
761 struct icmphdr *icmp;
763 ping_dst_ip = _ping_dst_ip;
768 fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP,
770 icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));
771 icmp->type = ICMP_ECHO_REQUEST;
774 icmp->options.echo.id = 0xd476;
775 icmp->options.echo.seq = 1;
777 memset(icmp->payload.data, '*', sizeof(icmp->payload.data));
780 checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1);
781 send_ipv4(fd, packet, sizeof(struct iphdr) + sizeof(struct icmphdr));
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
789 * @return ping_dst_ip host IPv4 address
791 uint32_t pong_ipv4(void)
797 * ICMP: Handles ICMP-packets according to Receive-handle diagram.
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)
806 static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet,
809 struct icmphdr *icmp = (struct icmphdr *) packet;
812 case ICMP_ECHO_REPLY:
813 if (icmp->options.echo.id != 0xd476)
815 if (icmp->options.echo.seq != 1)
817 if(ping_dst_ip != iph->ip_src
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;
827 switch(bad_iph->ip_p) {
829 handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize
830 - sizeof(struct icmphdr)
831 - sizeof(struct iphdr), icmp->code);
834 handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize
835 - sizeof(struct icmphdr)
836 - sizeof(struct iphdr), icmp->code);
841 case ICMP_SRC_QUENCH:
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;
850 fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize,
851 IPTYPE_ICMP, 0, iph->ip_src);
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);
860 send_ipv4(fd, reply_packet, sizeof(struct iphdr) + packetsize);
863 case ICMP_TIME_EXCEEDED:
865 case ICMP_PARAMETER_PROBLEM:
867 case ICMP_TIMESTAMP_REQUEST:
869 case ICMP_TIMESTAMP_REPLY:
871 case ICMP_INFORMATION_REQUEST:
873 case ICMP_INFORMATION_REPLY: