diff options
Diffstat (limited to 'qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c')
-rw-r--r-- | qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c | 877 |
1 files changed, 0 insertions, 877 deletions
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c deleted file mode 100644 index 2b92c77c4..000000000 --- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c +++ /dev/null @@ -1,877 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2004, 2008 IBM Corporation - * All rights reserved. - * This program and the accompanying materials - * are made available under the terms of the BSD License - * which accompanies this distribution, and is available at - * http://www.opensource.org/licenses/bsd-license.php - * - * Contributors: - * IBM Corporation - initial implementation - *****************************************************************************/ - - -/********************** DEFINITIONS & DECLARATIONS ***********************/ - -#include <ipv4.h> -#include <udp.h> -#include <tcp.h> -#include <ethernet.h> -#include <time.h> -#include <sys/socket.h> -#include <string.h> - -/* ARP Message types */ -#define ARP_REQUEST 1 -#define ARP_REPLY 2 - -/* ARP talbe size (+1) */ -#define ARP_ENTRIES 10 - -/* ICMP Message types */ -#define ICMP_ECHO_REPLY 0 -#define ICMP_DST_UNREACHABLE 3 -#define ICMP_SRC_QUENCH 4 -#define ICMP_REDIRECT 5 -#define ICMP_ECHO_REQUEST 8 -#define ICMP_TIME_EXCEEDED 11 -#define ICMP_PARAMETER_PROBLEM 12 -#define ICMP_TIMESTAMP_REQUEST 13 -#define ICMP_TIMESTAMP_REPLY 14 -#define ICMP_INFORMATION_REQUEST 15 -#define ICMP_INFORMATION_REPLY 16 - -/** \struct arp_entry - * A entry that describes a mapping between IPv4- and MAC-address. - */ -typedef struct arp_entry arp_entry_t; -struct arp_entry { - uint32_t ipv4_addr; - uint8_t mac_addr[6]; - uint8_t eth_frame[ETH_MTU_SIZE]; - int eth_len; - int pkt_pending; -}; - -/** \struct icmphdr - * ICMP packet - */ -struct icmphdr { - unsigned char type; - unsigned char code; - unsigned short int checksum; - union { - /* for type 3 "Destination Unreachable" */ - unsigned int unused; - /* for type 0 and 8 */ - struct echo { - unsigned short int id; - unsigned short int seq; - } echo; - } options; - union { - /* payload for destination unreachable */ - struct dun { - unsigned char iphdr[20]; - unsigned char data[64]; - } dun; - /* payload for echo or echo reply */ - /* maximum size supported is 84 */ - unsigned char data[84]; - } payload; -}; - -/****************************** PROTOTYPES *******************************/ - -static unsigned short checksum(unsigned short *packet, int words); - -static void arp_send_request(int fd, uint32_t dest_ip); - -static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac); - -static void fill_arphdr(uint8_t * packet, uint8_t opcode, - const uint8_t * src_mac, uint32_t src_ip, - const uint8_t * dest_mac, uint32_t dest_ip); - -static arp_entry_t *lookup_mac_addr(uint32_t ipv4_addr); - -static void fill_udp_checksum(struct iphdr *ipv4_hdr); - -static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, - int32_t packetsize); - -/****************************** LOCAL VARIABLES **************************/ - -/* Routing parameters */ -static uint32_t own_ip = 0; -static uint32_t multicast_ip = 0; -static uint32_t router_ip = 0; -static uint32_t subnet_mask = 0; - -/* helper variables */ -static uint32_t ping_dst_ip; -static const uint8_t null_mac_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; -static uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - -/* There are only (ARP_ENTRIES-1) effective entries because - * the entry that is pointed by arp_producer is never used. - */ -static unsigned int arp_consumer = 0; -static unsigned int arp_producer = 0; -static arp_entry_t arp_table[ARP_ENTRIES]; - -static uint8_t pending_pkt_frame[ETH_MTU_SIZE]; -static int pending_pkt_len; - -/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ -int (*send_ip) (int fd, void *, int); - -/***************************** IMPLEMENTATION ****************************/ - -/** - * IPv4: Initialize the environment for the IPv4 layer. - */ -static void ipv4_init(void) -{ - int i; - - ping_dst_ip = 0; - - // clear ARP table - arp_consumer = 0; - arp_producer = 0; - for(i=0; i<ARP_ENTRIES; ++i) { - arp_table[i].ipv4_addr = 0; - memset(arp_table[i].mac_addr, 0, 6); - arp_table[i].eth_len = 0; - arp_table[i].pkt_pending = 0; - } - - /* Set IP send function to send_ipv4() */ - send_ip = &send_ipv4; -} - -/** - * IPv4: Set the own IPv4 address. - * - * @param _own_ip client IPv4 address (e.g. 127.0.0.1) - */ -void set_ipv4_address(uint32_t _own_ip) -{ - own_ip = _own_ip; - ipv4_init(); -} - -/** - * IPv4: Get the own IPv4 address. - * - * @return client IPv4 address (e.g. 127.0.0.1) - */ -uint32_t get_ipv4_address(void) -{ - return own_ip; -} - -/** - * IPv4: Set the IPv4 multicast address. - * - * @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255) - */ -void set_ipv4_multicast(uint32_t _multicast_ip) -{ - // is this IP Multicast out of range (224.0.0.0 - 239.255.255.255) - if((htonl(_multicast_ip) < 0xE0000000) - || (htonl(_multicast_ip) > 0xEFFFFFFF)) { - multicast_ip = 0; - memset(multicast_mac, 0xFF, 6); - return; - } - - multicast_ip = _multicast_ip; - multicast_mac[0] = 0x01; - multicast_mac[1] = 0x00; - multicast_mac[2] = 0x5E; - multicast_mac[3] = (uint8_t) 0x7F & (multicast_ip >> 16); - multicast_mac[4] = (uint8_t) 0xFF & (multicast_ip >> 8); - multicast_mac[5] = (uint8_t) 0xFF & (multicast_ip >> 0); -} - -/** - * IPv4: Get the IPv4 multicast address. - * - * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set) - */ -uint32_t get_ipv4_multicast(void) -{ - return multicast_ip; -} - -/** - * IPv4: Set the routers IPv4 address. - * - * @param _router_ip router IPv4 address - */ -void set_ipv4_router(uint32_t _router_ip) -{ - router_ip = _router_ip; - ipv4_init(); -} - -/** - * IPv4: Get the routers IPv4 address. - * - * @return router IPv4 address - */ -uint32_t get_ipv4_router(void) -{ - return router_ip; -} - -/** - * IPv4: Set the subnet mask. - * - * @param _subnet_mask netmask of the own IPv4 address - */ -void set_ipv4_netmask(uint32_t _subnet_mask) -{ - subnet_mask = _subnet_mask; - ipv4_init(); -} - -/** - * IPv4: Get the subnet mask. - * - * @return netmask of the own IPv4 address - */ -uint32_t get_ipv4_netmask(void) -{ - return subnet_mask; -} - -/** - * IPv4: Creates IP-packet. Places IP-header in a packet and fills it - * with corresponding information. - * <p> - * Use this function with similar functions for other network layers - * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr). - * - * @param packet Points to the place where IP-header must be placed. - * @param packetsize Size of the packet in bytes incl. this hdr and data. - * @param ip_proto Type of the next level protocol (e.g. UDP). - * @param ip_src Sender IP address - * @param ip_dst Receiver IP address - * @see iphdr - * @see fill_ethhdr - * @see fill_udphdr - * @see fill_dnshdr - * @see fill_btphdr - */ -void fill_iphdr(uint8_t * packet, uint16_t packetsize, - uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) -{ - struct iphdr * iph = (struct iphdr *) packet; - - iph -> ip_hlv = 0x45; - iph -> ip_tos = 0x10; - iph -> ip_len = htons(packetsize); - iph -> ip_id = htons(0); - iph -> ip_off = 0; - iph -> ip_ttl = 0xFF; - iph -> ip_p = ip_proto; - iph -> ip_src = htonl(ip_src); - iph -> ip_dst = htonl(ip_dst); - iph -> ip_sum = 0; -} - -/** - * IPv4: Handles IPv4-packets according to Receive-handle diagram. - * - * @param fd socket fd - * @param ip_packet IP-packet to be handled - * @param packetsize Length of the packet - * @return ZERO - packet handled successfully; - * NON ZERO - packet was not handled (e.g. bad format) - * @see receive_ether - * @see iphdr - */ -int8_t handle_ipv4(int fd, uint8_t * ip_packet, uint32_t packetsize) -{ - struct iphdr * iph; - int32_t old_sum; - static uint8_t ip_heap[65536 + ETH_MTU_SIZE]; - - if (packetsize < sizeof(struct iphdr)) - return -1; // packet is too small - - iph = (struct iphdr * ) ip_packet; - - /* Drop it if destination IPv4 address is no IPv4 Broadcast, no - * registered IPv4 Multicast and not our Unicast address - */ - if((multicast_ip == 0 && iph->ip_dst >= 0xE0000000 && iph->ip_dst <= 0xEFFFFFFF) - || (multicast_ip != iph->ip_dst && iph->ip_dst != 0xFFFFFFFF && - own_ip != 0 && iph->ip_dst != own_ip)) { - return -1; - } - - old_sum = iph -> ip_sum; - iph -> ip_sum = 0; - if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1)) - return -1; // Wrong IP checksum - - // is it the first fragment in a packet? - if (((iph -> ip_off) & 0x1FFF) == 0) { - // is it part of more fragments? - if (((iph -> ip_off) & 0x2000) == 0x2000) { - memcpy(ip_heap, ip_packet, iph->ip_len); - return 0; - } - } - // it's not the first fragment - else { - // get the first fragment - struct iphdr * iph_first = (struct iphdr * ) ip_heap; - - // is this fragment not part of the first one, then exit - if ((iph_first->ip_id != iph->ip_id ) || - (iph_first->ip_p != iph->ip_p ) || - (iph_first->ip_src != iph->ip_src) || - (iph_first->ip_dst != iph->ip_dst)) { - return 0; - } - - // this fragment is part of the first one! - memcpy(ip_heap + sizeof(struct iphdr) + - ((iph -> ip_off) & 0x1FFF) * 8, - ip_packet + sizeof(struct iphdr), - iph -> ip_len - sizeof(struct iphdr)); - - // is it part of more fragments? Then return. - if (((iph -> ip_off) & 0x2000) == 0x2000) { - return 0; - } - - // packet is completly reassambled now! - - // recalculate ip_len and set iph and ip_packet to the - iph_first->ip_len = iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8; - - // set iph and ip_packet to the resulting packet. - ip_packet = ip_heap; - iph = (struct iphdr * ) ip_packet; - } - - switch (iph -> ip_p) { - case IPTYPE_ICMP: - return handle_icmp(fd, iph, ip_packet + sizeof(struct iphdr), - iph -> ip_len - sizeof(struct iphdr)); - case IPTYPE_UDP: - return handle_udp(fd, ip_packet + sizeof(struct iphdr), - iph -> ip_len - sizeof(struct iphdr)); - case IPTYPE_TCP: - return handle_tcp(ip_packet + sizeof(struct iphdr), - iph -> ip_len - sizeof(struct iphdr)); - default: - break; - } - return -1; // Unknown protocol -} - -/** - * IPv4: Send IPv4-packets. - * - * Before the packet is sent there are some patcches performed: - * - IPv4 source address is replaced by our unicast IPV4 address - * if it is set to 0 or 1 - * - IPv4 destination address is replaced by our multicast IPV4 address - * if it is set to 1 - * - IPv4 checksum is calculaded. - * - If payload type is UDP, then the UDP checksum is calculated also. - * - * We send an ARP request first, if this is the first packet sent to - * the declared IPv4 destination address. In this case we store the - * the packet and send it later if we receive the ARP response. - * If the MAC address is known already, then we send the packet immediately. - * If there is already an ARP request pending, then we drop this packet - * and send again an ARP request. - * - * @param fd socket fd - * @param ip_packet IP-packet to be handled - * @param packetsize Length of the packet - * @return -2 - packet dropped (MAC address not resolved - ARP request pending) - * -1 - packet dropped (bad format) - * 0 - packet stored (ARP request sent - packet will be sent if - * ARP response is received) - * >0 - packet send (number of transmitted bytes is returned) - * - * @see receive_ether - * @see iphdr - */ -int send_ipv4(int fd, void* buffer, int len) -{ - arp_entry_t *arp_entry = 0; - struct iphdr *ip; - const uint8_t *mac_addr = 0; - uint32_t ip_dst = 0; - - if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE) - return -1; - - ip = (struct iphdr *) buffer; - - /* Replace source IPv4 address with our own unicast IPv4 address - * if it's 0 (= own unicast source address not specified). - */ - if(ip->ip_src == 0) { - ip->ip_src = htonl( own_ip ); - } - /* Replace source IPv4 address with our unicast IPv4 address and - * replace destination IPv4 address with our multicast IPv4 address - * if source address is set to 1. - */ - else if(ip->ip_src == 1) { - ip->ip_src = htonl( own_ip ); - ip->ip_dst = htonl( multicast_ip ); - } - - // Calculate the IPv4 checksum - ip->ip_sum = 0; - ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1); - - // if payload type is UDP, then we need to calculate the - // UDP checksum that depends on the IP header - if(ip->ip_p == IPTYPE_UDP) { - fill_udp_checksum(ip); - } - - ip_dst = ip->ip_dst; - // Check if the MAC address is already cached - if(~ip->ip_dst == 0 - || ( ((~subnet_mask) & ip->ip_dst) == ~subnet_mask && - ( subnet_mask & ip->ip_dst) == (subnet_mask & own_ip))) { - arp_entry = &arp_table[arp_producer]; - mac_addr = broadcast_mac; - } - else if(ip->ip_dst == multicast_ip) { - arp_entry = &arp_table[arp_producer]; - mac_addr = multicast_mac; - } - else { - // Check if IP address is in the same subnet as we are - if((subnet_mask & own_ip) == (subnet_mask & ip->ip_dst)) - arp_entry = lookup_mac_addr(ip->ip_dst); - // if not then we need to know the router's IP address - else { - ip_dst = router_ip; - arp_entry = lookup_mac_addr(router_ip); - } - if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0) - mac_addr = arp_entry->mac_addr; - } - - // If we could not resolv the MAC address by our own... - if(!mac_addr) { - // send the ARP request - arp_send_request(fd, ip_dst); - - // drop the current packet if there is already a ARP request pending - if(arp_entry) - return -2; - - // take the next entry in the ARP table to prepare a the new ARP entry. - arp_entry = &arp_table[arp_producer]; - arp_producer = (arp_producer+1)%ARP_ENTRIES; - - // if ARP table is full then we must drop the oldes entry. - if(arp_consumer == arp_producer) - arp_consumer = (arp_consumer+1)%ARP_ENTRIES; - - // store the packet to be send if the ARP reply is received - arp_entry->pkt_pending = 1; - arp_entry->ipv4_addr = ip_dst; - memset(arp_entry->mac_addr, 0, 6); - fill_ethhdr (pending_pkt_frame, htons(ETHERTYPE_IP), - get_mac_address(), null_mac_addr); - memcpy(&pending_pkt_frame[sizeof(struct ethhdr)], - buffer, len); - pending_pkt_len = len + sizeof(struct ethhdr); - - set_timer(TICKS_SEC); - do { - receive_ether(fd); - if (!arp_entry->eth_len) - break; - } while (get_timer() > 0); - - return 0; - } - - // Send the packet with the known MAC address - fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP), - get_mac_address(), mac_addr); - memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len); - return send_ether(fd, arp_entry->eth_frame, len + sizeof(struct ethhdr)); -} - -/** - * IPv4: Calculate UDP checksum. Places the result into the UDP-header. - * <p> - * Use this function after filling the UDP payload. - * - * @param ipv4_hdr Points to the place where IPv4-header starts. - */ -static void fill_udp_checksum(struct iphdr *ipv4_hdr) -{ - unsigned i; - unsigned long checksum = 0; - struct iphdr ip_hdr; - char *ptr; - udp_hdr_t *udp_hdr; - - udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1); - udp_hdr->uh_sum = 0; - - memset(&ip_hdr, 0, sizeof(struct iphdr)); - ip_hdr.ip_src = ipv4_hdr->ip_src; - ip_hdr.ip_dst = ipv4_hdr->ip_dst; - ip_hdr.ip_len = udp_hdr->uh_ulen; - ip_hdr.ip_p = ipv4_hdr->ip_p; - - ptr = (char*) udp_hdr; - for (i = 0; i < udp_hdr->uh_ulen; i+=2) - checksum += *((uint16_t*) &ptr[i]); - - ptr = (char*) &ip_hdr; - for (i = 0; i < sizeof(struct iphdr); i+=2) - checksum += *((uint16_t*) &ptr[i]); - - checksum = (checksum >> 16) + (checksum & 0xffff); - checksum += (checksum >> 16); - udp_hdr->uh_sum = ~checksum; - - /* As per RFC 768, if the computed checksum is zero, - * it is transmitted as all ones (the equivalent in - * one's complement arithmetic). - */ - if (udp_hdr->uh_sum == 0) - udp_hdr->uh_sum = ~udp_hdr->uh_sum; -} - -/** - * IPv4: Calculates checksum for IP header. - * - * @param packet Points to the IP-header - * @param words Size of the packet in words incl. IP-header and data. - * @return Checksum - * @see iphdr - */ -static unsigned short checksum(unsigned short * packet, int words) -{ - unsigned long checksum; - - for (checksum = 0; words > 0; words--) - checksum += *packet++; - checksum = (checksum >> 16) + (checksum & 0xffff); - checksum += (checksum >> 16); - - return ~checksum; -} - -static arp_entry_t* lookup_mac_addr(uint32_t ipv4_addr) -{ - unsigned int i; - - for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) { - if(arp_table[i].ipv4_addr == ipv4_addr) - return &arp_table[i]; - } - return 0; -} - - -/** - * ARP: Sends an ARP-request package. - * For given IPv4 retrieves MAC via ARP (makes several attempts) - * - * @param fd socket fd - * @param dest_ip IP of the host which MAC should be obtained - */ -static void arp_send_request(int fd, uint32_t dest_ip) -{ - arp_entry_t *arp_entry = &arp_table[arp_producer]; - - memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr)); - fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST, - get_mac_address(), own_ip, broadcast_mac, dest_ip); - fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, - get_mac_address(), broadcast_mac); - - send_ether(fd, arp_entry->eth_frame, - sizeof(struct ethhdr) + sizeof(struct arphdr)); -} - -/** - * ARP: Sends an ARP-reply package. - * This package is used to serve foreign requests (in case IP in - * foreign request matches our host IP). - * - * @param fd socket fd - * @param src_ip requester IP address (foreign IP) - * @param src_mac requester MAC address (foreign MAC) - */ -static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac) -{ - arp_entry_t *arp_entry = &arp_table[arp_producer]; - - memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr)); - fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, - get_mac_address(), src_mac); - fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY, - get_mac_address(), own_ip, src_mac, src_ip); - - send_ether(fd, arp_entry->eth_frame, - sizeof(struct ethhdr) + sizeof(struct arphdr)); -} - -/** - * ARP: Creates ARP package. Places ARP-header in a packet and fills it - * with corresponding information. - * <p> - * Use this function with similar functions for other network layers - * (fill_ethhdr). - * - * @param packet Points to the place where ARP-header must be placed. - * @param opcode Identifies is it request (ARP_REQUEST) - * or reply (ARP_REPLY) package. - * @param src_mac sender MAC address - * @param src_ip sender IP address - * @param dest_mac receiver MAC address - * @param dest_ip receiver IP address - * @see arphdr - * @see fill_ethhdr - */ -static void fill_arphdr(uint8_t * packet, uint8_t opcode, - const uint8_t * src_mac, uint32_t src_ip, - const uint8_t * dest_mac, uint32_t dest_ip) -{ - struct arphdr * arph = (struct arphdr *) packet; - - arph -> hw_type = htons(1); - arph -> proto_type = htons(ETHERTYPE_IP); - arph -> hw_len = 6; - arph -> proto_len = 4; - arph -> opcode = htons(opcode); - - memcpy(arph->src_mac, src_mac, 6); - arph->src_ip = htonl(src_ip); - memcpy(arph->dest_mac, dest_mac, 6); - arph->dest_ip = htonl(dest_ip); -} - -/** - * ARP: Handles ARP-messages according to Receive-handle diagram. - * Updates arp_table for outstanding ARP requests (see arp_getmac). - * - * @param fd socket fd - * @param packet ARP-packet to be handled - * @param packetsize length of the packet - * @return ZERO - packet handled successfully; - * NON ZERO - packet was not handled (e.g. bad format) - * @see arp_getmac - * @see receive_ether - * @see arphdr - */ -int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize) -{ - struct arphdr * arph = (struct arphdr *) packet; - - if (packetsize < sizeof(struct arphdr)) - return -1; // Packet is too small - - if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP)) - return -1; // Unknown hardware or unsupported protocol - - if (arph -> dest_ip != htonl(own_ip)) - return -1; // receiver IP doesn't match our IP - - switch(htons(arph -> opcode)) { - case ARP_REQUEST: - // foreign request - if(own_ip != 0) - arp_send_reply(fd, htonl(arph->src_ip), arph -> src_mac); - return 0; // no error - case ARP_REPLY: { - unsigned int i; - // if it is not for us -> return immediately - if(memcmp(get_mac_address(), arph->dest_mac, 6)) { - return 0; // no error - } - - if(arph->src_ip == 0) { - // we are not interested for a MAC address if - // the IPv4 address is 0.0.0.0 or ff.ff.ff.ff - return -1; - } - - // now let's find the corresponding entry in the ARP table - - for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) { - if(arp_table[i].ipv4_addr == arph->src_ip) - break; - } - if(i == arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr, 6) != 0) { - // we have not asked to resolve this IPv4 address ! - return -1; - } - - memcpy(arp_table[i].mac_addr, arph->src_mac, 6); - - // do we have something to send - if (arp_table[i].pkt_pending) { - struct ethhdr * ethh = (struct ethhdr *) pending_pkt_frame; - memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6); - - send_ether(fd, pending_pkt_frame, pending_pkt_len); - arp_table[i].pkt_pending = 0; - arp_table[i].eth_len = 0; - } - return 0; // no error - } - default: - break; - } - return -1; // Invalid message type -} - -/** - * ICMP: Send an ICMP Echo request to destination IPv4 address. - * This function does also set a global variable to the - * destination IPv4 address. If there is an ICMP Echo Reply - * received later then the variable is set back to 0. - * In other words, reading a value of 0 form this variable - * means that an answer to the request has been arrived. - * - * @param fd socket descriptor - * @param _ping_dst_ip destination IPv4 address - */ -void ping_ipv4(int fd, uint32_t _ping_dst_ip) -{ - unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)]; - struct icmphdr *icmp; - - ping_dst_ip = _ping_dst_ip; - - if(ping_dst_ip == 0) - return; - - fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP, - 0, ping_dst_ip); - icmp = (struct icmphdr *) (packet + sizeof(struct iphdr)); - icmp->type = ICMP_ECHO_REQUEST; - icmp->code = 0; - icmp->checksum = 0; - icmp->options.echo.id = 0xd476; - icmp->options.echo.seq = 1; - - memset(icmp->payload.data, '*', sizeof(icmp->payload.data)); - - icmp->checksum = - checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1); - send_ipv4(fd, packet, sizeof(struct iphdr) + sizeof(struct icmphdr)); -} - -/** - * ICMP: Return host IPv4 address that we are waiting for a - * ICMP Echo reply message. If this value is 0 then we have - * received an reply. - * - * @return ping_dst_ip host IPv4 address - */ -uint32_t pong_ipv4(void) -{ - return ping_dst_ip; -} - -/** - * ICMP: Handles ICMP-packets according to Receive-handle diagram. - * - * @param fd socket fd - * @param icmp_packet ICMP-packet to be handled - * @param packetsize Length of the packet - * @return ZERO - packet handled successfully; - * NON ZERO - packet was not handled (e.g. bad format) - * @see handle_ipv4 - */ -static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, - int32_t packetsize) -{ - struct icmphdr *icmp = (struct icmphdr *) packet; - - switch(icmp->type) { - case ICMP_ECHO_REPLY: - if (icmp->options.echo.id != 0xd476) - return -1; - if (icmp->options.echo.seq != 1) - return -1; - if(ping_dst_ip != iph->ip_src - || ping_dst_ip == 0) - return -1; - ping_dst_ip = 0; - break; - case ICMP_DST_UNREACHABLE: { - // We've got Destination Unreachable msg - // Inform corresponding upper network layers - struct iphdr * bad_iph = (struct iphdr * ) &icmp->payload; - - switch(bad_iph->ip_p) { - case IPTYPE_TCP: - handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize - - sizeof(struct icmphdr) - - sizeof(struct iphdr), icmp->code); - break; - case IPTYPE_UDP: - handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize - - sizeof(struct icmphdr) - - sizeof(struct iphdr), icmp->code); - break; - } - break; - } - case ICMP_SRC_QUENCH: - break; - case ICMP_REDIRECT: - break; - case ICMP_ECHO_REQUEST: { - // We've got an Echo Request - answer with Echo Replay msg - unsigned char reply_packet[sizeof(struct iphdr) + packetsize]; - struct icmphdr *reply_icmph; - - fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize, - IPTYPE_ICMP, 0, iph->ip_src); - - reply_icmph = (struct icmphdr *) &reply_packet[sizeof(struct iphdr)]; - memcpy(reply_icmph, packet, packetsize); - reply_icmph -> type = ICMP_ECHO_REPLY; - reply_icmph -> checksum = 0; - reply_icmph->checksum = checksum((unsigned short *) reply_icmph, - sizeof(struct icmphdr) >> 1); - - send_ipv4(fd, reply_packet, sizeof(struct iphdr) + packetsize); - break; - } - case ICMP_TIME_EXCEEDED: - break; - case ICMP_PARAMETER_PROBLEM: - break; - case ICMP_TIMESTAMP_REQUEST: - break; - case ICMP_TIMESTAMP_REPLY: - break; - case ICMP_INFORMATION_REQUEST: - break; - case ICMP_INFORMATION_REPLY: - break; - } - return 0; -} |