Annotation of qemu/roms/ipxe/src/net/arp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: #include <stdint.h>
        !            22: #include <string.h>
        !            23: #include <byteswap.h>
        !            24: #include <errno.h>
        !            25: #include <ipxe/if_ether.h>
        !            26: #include <ipxe/if_arp.h>
        !            27: #include <ipxe/iobuf.h>
        !            28: #include <ipxe/netdevice.h>
        !            29: #include <ipxe/arp.h>
        !            30: 
        !            31: /** @file
        !            32:  *
        !            33:  * Address Resolution Protocol
        !            34:  *
        !            35:  * This file implements the address resolution protocol as defined in
        !            36:  * RFC826.  The implementation is media-independent and
        !            37:  * protocol-independent; it is not limited to Ethernet or to IPv4.
        !            38:  *
        !            39:  */
        !            40: 
        !            41: /** An ARP cache entry */
        !            42: struct arp_entry {
        !            43:        /** Network-layer protocol */
        !            44:        struct net_protocol *net_protocol;
        !            45:        /** Link-layer protocol */
        !            46:        struct ll_protocol *ll_protocol;
        !            47:        /** Network-layer address */
        !            48:        uint8_t net_addr[MAX_NET_ADDR_LEN];
        !            49:        /** Link-layer address */
        !            50:        uint8_t ll_addr[MAX_LL_ADDR_LEN];
        !            51: };
        !            52: 
        !            53: /** Number of entries in the ARP cache
        !            54:  *
        !            55:  * This is a global cache, covering all network interfaces,
        !            56:  * network-layer protocols and link-layer protocols.
        !            57:  */
        !            58: #define NUM_ARP_ENTRIES 4
        !            59: 
        !            60: /** The ARP cache */
        !            61: static struct arp_entry arp_table[NUM_ARP_ENTRIES];
        !            62: #define arp_table_end &arp_table[NUM_ARP_ENTRIES]
        !            63: 
        !            64: static unsigned int next_new_arp_entry = 0;
        !            65: 
        !            66: struct net_protocol arp_protocol __net_protocol;
        !            67: 
        !            68: /**
        !            69:  * Find entry in the ARP cache
        !            70:  *
        !            71:  * @v ll_protocol      Link-layer protocol
        !            72:  * @v net_protocol     Network-layer protocol
        !            73:  * @v net_addr         Network-layer address
        !            74:  * @ret arp            ARP cache entry, or NULL if not found
        !            75:  *
        !            76:  */
        !            77: static struct arp_entry *
        !            78: arp_find_entry ( struct ll_protocol *ll_protocol,
        !            79:                 struct net_protocol *net_protocol,
        !            80:                 const void *net_addr ) {
        !            81:        struct arp_entry *arp;
        !            82: 
        !            83:        for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
        !            84:                if ( ( arp->ll_protocol == ll_protocol ) &&
        !            85:                     ( arp->net_protocol == net_protocol ) &&
        !            86:                     ( memcmp ( arp->net_addr, net_addr,
        !            87:                                net_protocol->net_addr_len ) == 0 ) )
        !            88:                        return arp;
        !            89:        }
        !            90:        return NULL;
        !            91: }
        !            92: 
        !            93: /**
        !            94:  * Look up media-specific link-layer address in the ARP cache
        !            95:  *
        !            96:  * @v netdev           Network device
        !            97:  * @v net_protocol     Network-layer protocol
        !            98:  * @v dest_net_addr    Destination network-layer address
        !            99:  * @v source_net_addr  Source network-layer address
        !           100:  * @ret dest_ll_addr   Destination link layer address
        !           101:  * @ret rc             Return status code
        !           102:  *
        !           103:  * This function will use the ARP cache to look up the link-layer
        !           104:  * address for the link-layer protocol associated with the network
        !           105:  * device and the given network-layer protocol and addresses.  If
        !           106:  * found, the destination link-layer address will be filled in in @c
        !           107:  * dest_ll_addr.
        !           108:  *
        !           109:  * If no address is found in the ARP cache, an ARP request will be
        !           110:  * transmitted on the specified network device and -ENOENT will be
        !           111:  * returned.
        !           112:  */
        !           113: int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
        !           114:                  const void *dest_net_addr, const void *source_net_addr,
        !           115:                  void *dest_ll_addr ) {
        !           116:        struct ll_protocol *ll_protocol = netdev->ll_protocol;
        !           117:        const struct arp_entry *arp;
        !           118:        struct io_buffer *iobuf;
        !           119:        struct arphdr *arphdr;
        !           120:        int rc;
        !           121: 
        !           122:        /* Look for existing entry in ARP table */
        !           123:        arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr );
        !           124:        if ( arp ) {
        !           125:                DBG ( "ARP cache hit: %s %s => %s %s\n",
        !           126:                      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
        !           127:                      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
        !           128:                memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len);
        !           129:                return 0;
        !           130:        }
        !           131:        DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
        !           132:              net_protocol->ntoa ( dest_net_addr ) );
        !           133: 
        !           134:        /* Allocate ARP packet */
        !           135:        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
        !           136:                          2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
        !           137:        if ( ! iobuf )
        !           138:                return -ENOMEM;
        !           139:        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        !           140: 
        !           141:        /* Build up ARP request */
        !           142:        arphdr = iob_put ( iobuf, sizeof ( *arphdr ) );
        !           143:        arphdr->ar_hrd = ll_protocol->ll_proto;
        !           144:        arphdr->ar_hln = ll_protocol->ll_addr_len;
        !           145:        arphdr->ar_pro = net_protocol->net_proto;
        !           146:        arphdr->ar_pln = net_protocol->net_addr_len;
        !           147:        arphdr->ar_op = htons ( ARPOP_REQUEST );
        !           148:        memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
        !           149:                 netdev->ll_addr, ll_protocol->ll_addr_len );
        !           150:        memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
        !           151:                 source_net_addr, net_protocol->net_addr_len );
        !           152:        memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
        !           153:                 0, ll_protocol->ll_addr_len );
        !           154:        memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
        !           155:                 dest_net_addr, net_protocol->net_addr_len );
        !           156: 
        !           157:        /* Transmit ARP request */
        !           158:        if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
        !           159:                             netdev->ll_broadcast, netdev->ll_addr ) ) != 0 )
        !           160:                return rc;
        !           161: 
        !           162:        return -ENOENT;
        !           163: }
        !           164: 
        !           165: /**
        !           166:  * Identify ARP protocol
        !           167:  *
        !           168:  * @v net_proto                        Network-layer protocol, in network-endian order
        !           169:  * @ret arp_net_protocol       ARP protocol, or NULL
        !           170:  *
        !           171:  */
        !           172: static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
        !           173:        struct arp_net_protocol *arp_net_protocol;
        !           174: 
        !           175:        for_each_table_entry ( arp_net_protocol, ARP_NET_PROTOCOLS ) {
        !           176:                if ( arp_net_protocol->net_protocol->net_proto == net_proto ) {
        !           177:                        return arp_net_protocol;
        !           178:                }
        !           179:        }
        !           180:        return NULL;
        !           181: }
        !           182: 
        !           183: /**
        !           184:  * Process incoming ARP packets
        !           185:  *
        !           186:  * @v iobuf            I/O buffer
        !           187:  * @v netdev           Network device
        !           188:  * @v ll_source                Link-layer source address
        !           189:  * @ret rc             Return status code
        !           190:  *
        !           191:  * This handles ARP requests and responses as detailed in RFC826.  The
        !           192:  * method detailed within the RFC is pretty optimised, handling
        !           193:  * requests and responses with basically a single code path and
        !           194:  * avoiding the need for extraneous ARP requests; read the RFC for
        !           195:  * details.
        !           196:  */
        !           197: static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
        !           198:                    const void *ll_dest __unused,
        !           199:                    const void *ll_source __unused ) {
        !           200:        struct arphdr *arphdr = iobuf->data;
        !           201:        struct arp_net_protocol *arp_net_protocol;
        !           202:        struct net_protocol *net_protocol;
        !           203:        struct ll_protocol *ll_protocol;
        !           204:        struct arp_entry *arp;
        !           205:        int merge = 0;
        !           206: 
        !           207:        /* Identify network-layer and link-layer protocols */
        !           208:        arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
        !           209:        if ( ! arp_net_protocol )
        !           210:                goto done;
        !           211:        net_protocol = arp_net_protocol->net_protocol;
        !           212:        ll_protocol = netdev->ll_protocol;
        !           213: 
        !           214:        /* Sanity checks */
        !           215:        if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
        !           216:             ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
        !           217:             ( arphdr->ar_pln != net_protocol->net_addr_len ) )
        !           218:                goto done;
        !           219: 
        !           220:        /* See if we have an entry for this sender, and update it if so */
        !           221:        arp = arp_find_entry ( ll_protocol, net_protocol,
        !           222:                               arp_sender_pa ( arphdr ) );
        !           223:        if ( arp ) {
        !           224:                memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
        !           225:                         arphdr->ar_hln );
        !           226:                merge = 1;
        !           227:                DBG ( "ARP cache update: %s %s => %s %s\n",
        !           228:                      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
        !           229:                      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
        !           230:        }
        !           231: 
        !           232:        /* See if we own the target protocol address */
        !           233:        if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0)
        !           234:                goto done;
        !           235:        
        !           236:        /* Create new ARP table entry if necessary */
        !           237:        if ( ! merge ) {
        !           238:                arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
        !           239:                arp->ll_protocol = ll_protocol;
        !           240:                arp->net_protocol = net_protocol;
        !           241:                memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
        !           242:                         arphdr->ar_hln );
        !           243:                memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
        !           244:                         arphdr->ar_pln);
        !           245:                DBG ( "ARP cache add: %s %s => %s %s\n",
        !           246:                      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
        !           247:                      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
        !           248:        }
        !           249: 
        !           250:        /* If it's not a request, there's nothing more to do */
        !           251:        if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
        !           252:                goto done;
        !           253: 
        !           254:        /* Change request to a reply */
        !           255:        DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
        !           256:              net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
        !           257:              ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
        !           258:        arphdr->ar_op = htons ( ARPOP_REPLY );
        !           259:        memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
        !           260:                 arphdr->ar_hln + arphdr->ar_pln );
        !           261:        memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
        !           262: 
        !           263:        /* Send reply */
        !           264:        net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
        !           265:                 arp_target_ha ( arphdr ), netdev->ll_addr );
        !           266: 
        !           267:  done:
        !           268:        free_iob ( iobuf );
        !           269:        return 0;
        !           270: }
        !           271: 
        !           272: /**
        !           273:  * Transcribe ARP address
        !           274:  *
        !           275:  * @v net_addr ARP address
        !           276:  * @ret string "<ARP>"
        !           277:  *
        !           278:  * This operation is meaningless for the ARP protocol.
        !           279:  */
        !           280: static const char * arp_ntoa ( const void *net_addr __unused ) {
        !           281:        return "<ARP>";
        !           282: }
        !           283: 
        !           284: /** ARP protocol */
        !           285: struct net_protocol arp_protocol __net_protocol = {
        !           286:        .name = "ARP",
        !           287:        .net_proto = htons ( ETH_P_ARP ),
        !           288:        .rx = arp_rx,
        !           289:        .ntoa = arp_ntoa,
        !           290: };

unix.superglobalmegacorp.com

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