Annotation of qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.