Annotation of qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c, revision 1.1.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.