コード例 #1
0
ファイル: arp_cache.c プロジェクト: 0xcc/tapip
int arp_insert(struct netdev *nd, unsigned short pro,
		unsigned int ipaddr, unsigned char *hwaddr)
{
	struct arpentry *ae;
	ae = arp_alloc();
	if (!ae)
		return -1;
	ae->ae_dev = nd;
	ae->ae_pro = pro;
	ae->ae_ttl = ARP_TIMEOUT;
	ae->ae_ipaddr = ipaddr;
	ae->ae_state = ARP_RESOLVED;
	hwacpy(ae->ae_hwaddr, hwaddr);
	return 0;
}
コード例 #2
0
/*------------------------------------------------------------------------
 * arp_resolve  -  Use ARP to resolve an IP address to an Ethernet address
 *------------------------------------------------------------------------
 */
status	arp_resolve (
    uint32	nxthop,			/* Next-hop address to resolve	*/
    byte	mac[ETH_ADDR_LEN]	/* Array into which Ethernet	*/
)				/*   address should be placed	*/
{
    intmask	mask;			/* Saved interrupt mask		*/
    struct	arppacket apkt;		/* Local packet buffer		*/
    int32	i;			/* Index into arpcache		*/
    int32	slot;			/* ARP table slot to use	*/
    struct	arpentry  *arptr;	/* Ptr to ARP cache entry	*/
    int32	msg;			/* Message returned by recvtime	*/

    /* Use MAC broadcast address for IP limited broadcast */

    if (nxthop == IP_BCAST) {
        memcpy(mac, NetData.ethbcast, ETH_ADDR_LEN);
        return OK;
    }

    /* Use MAC broadcast address for IP network broadcast */

    if (nxthop == NetData.ipbcast) {
        memcpy(mac, NetData.ethbcast, ETH_ADDR_LEN);
        return OK;
    }

    /* Ensure only one process uses ARP at a time */

    mask = disable();

    /* See if next hop address is already present in ARP cache */

    for (i=0; i<ARP_SIZ; i++) {
        arptr = &arpcache[i];
        if (arptr->arstate == AR_FREE) {
            continue;
        }
        if (arptr->arpaddr == nxthop) { /* Adddress is in cache	*/
            break;
        }
    }

    if (i < ARP_SIZ) {	/* Entry was found */

        /* If entry is resolved - handle and return */

        if (arptr->arstate == AR_RESOLVED) {
            memcpy(mac, arptr->arhaddr, ARP_HALEN);
            restore(mask);
            return OK;
        }

        /* Entry is already pending -  return error because	*/
        /*	only one process can be	waiting at a time	*/

        if (arptr->arstate == AR_PENDING) {
            restore(mask);
            return SYSERR;
        }
    }

    /* IP address not in cache -  allocate a new cache entry and	*/
    /*	send an ARP request to obtain the answer		*/

    slot = arp_alloc();
    if (slot == SYSERR) {
        restore(mask);
        return SYSERR;
    }

    arptr = &arpcache[slot];
    arptr->arstate = AR_PENDING;
    arptr->arpaddr = nxthop;
    arptr->arpid = currpid;

    /* Hand-craft an ARP Request packet */

    memcpy(apkt.arp_ethdst, NetData.ethbcast, ETH_ADDR_LEN);
    memcpy(apkt.arp_ethsrc, NetData.ethucast, ETH_ADDR_LEN);
    apkt.arp_ethtype = ETH_ARP;	  /* Packet type is ARP		*/
    apkt.arp_htype = ARP_HTYPE;	  /* Hardware type is Ethernet	*/
    apkt.arp_ptype = ARP_PTYPE;	  /* Protocol type is IP	*/
    apkt.arp_hlen = 0xff & ARP_HALEN; /* Ethernet MAC size in bytes	*/
    apkt.arp_plen = 0xff & ARP_PALEN; /* IP address size in bytes	*/
    apkt.arp_op = 0xffff & ARP_OP_REQ;/* ARP type is Request	*/
    memcpy(apkt.arp_sndha, NetData.ethucast, ARP_HALEN);
    apkt.arp_sndpa = NetData.ipucast; /* IP address of interface	*/
    memset(apkt.arp_tarha, '\0', ARP_HALEN); /* Target HA is unknown*/
    apkt.arp_tarpa = nxthop;	  /* Target protocol address	*/

    /* Convert ARP packet from host to net byte order */

    arp_hton(&apkt);

    /* Convert Ethernet header from host to net byte order */

    eth_hton((struct netpacket *)&apkt);

    /* Send the packet ARP_RETRY times and await response */

    msg = recvclr();
    for (i=0; i<ARP_RETRY; i++) {
        write(ETHER0, (char *)&apkt, sizeof(struct arppacket));
        msg = recvtime(ARP_TIMEOUT);
        if (msg == TIMEOUT) {
            continue;
        } else if (msg == SYSERR) {
            restore(mask);
            return SYSERR;
        } else {	/* entry is resolved */
            break;
        }
    }

    /* If no response, return TIMEOUT */

    if (msg == TIMEOUT) {
        arptr->arstate = AR_FREE;   /* Invalidate cache entry */
        restore(mask);
        return TIMEOUT;
    }

    /* Return hardware address */

    memcpy(mac, arptr->arhaddr, ARP_HALEN);
    restore(mask);
    return OK;
}
コード例 #3
0
/*------------------------------------------------------------------------
 * arp_in  -  Handle an incoming ARP packet
 *------------------------------------------------------------------------
 */
void	arp_in (
    struct arppacket *pktptr	/* Ptr to incoming packet	*/
)
{
    intmask	mask;			/* Saved interrupt mask		*/
    struct	arppacket apkt;		/* Local packet buffer		*/
    int32	slot;			/* Slot in cache		*/
    struct	arpentry  *arptr;	/* Ptr to ARP cache entry	*/
    bool8	found;			/* Is the sender's address in	*/
    /*   the cache?			*/

    /* Convert packet from network order to host order */

    arp_ntoh(pktptr);

    /* Verify ARP is for IPv4 and Ethernet */

    if ( (pktptr->arp_htype != ARP_HTYPE) ||
            (pktptr->arp_ptype != ARP_PTYPE) ) {
        freebuf((char *)pktptr);
        return;
    }

    /* Ensure only one process uses ARP at a time */

    mask = disable();

    /* Search cache for sender's IP address */

    found = FALSE;

    for (slot=0; slot < ARP_SIZ; slot++) {
        arptr = &arpcache[slot];

        /* Skip table entries that are unused */

        if (arptr->arstate == AR_FREE) {
            continue;
        }

        /* If sender's address matches, we've found it */

        if (arptr->arpaddr == pktptr->arp_sndpa) {
            found = TRUE;
            break;
        }
    }

    if (found) {

        /* Update sender's hardware address */

        memcpy(arptr->arhaddr, pktptr->arp_sndha, ARP_HALEN);

        /* If a process was waiting, inform the process */

        if (arptr->arstate == AR_PENDING) {
            /* Mark resolved and notify waiting process */
            arptr->arstate = AR_RESOLVED;
            arptr->time = clktime;
            send(arptr->arpid, OK);
        }
    }

    /* For an ARP reply, processing is complete */

    if (pktptr->arp_op == ARP_OP_RPLY) {
        freebuf((char *)pktptr);
        restore(mask);
        return;
    }

    /* The following is for an ARP request packet: if the local	*/
    /*  machine is not the target or the local IP address is not	*/
    /*  yet known, ignore the request (i.e., processing is complete)*/

    if ((!NetData.ipvalid) ||
            (pktptr->arp_tarpa != NetData.ipucast)) {
        freebuf((char *)pktptr);
        restore(mask);
        return;
    }

    /* Request has been sent to the local machine's address.  So,	*/
    /*   add sender's info to cache, if not already present		*/

    if (!found) {
        slot = arp_alloc();
        if (slot == SYSERR) {	/* Cache is full */
            kprintf("ARP cache overflow on interface\n");
            freebuf((char *)pktptr);
            restore(mask);
            return;
        }
        arptr = &arpcache[slot];
        arptr->arpaddr = pktptr->arp_sndpa;
        memcpy(arptr->arhaddr, pktptr->arp_sndha, ARP_HALEN);
        arptr->arstate = AR_RESOLVED;
    }

    /* Hand-craft an ARP reply packet and send back to requester	*/

    memcpy(apkt.arp_ethdst, pktptr->arp_sndha, ARP_HALEN);
    memcpy(apkt.arp_ethsrc, NetData.ethucast, ARP_HALEN);
    apkt.arp_ethtype= ETH_ARP;		/* Frame carries ARP	*/
    apkt.arp_htype	= ARP_HTYPE;		/* Hardware is Ethernet	*/
    apkt.arp_ptype	= ARP_PTYPE;		/* Protocol is IP	*/
    apkt.arp_hlen	= ARP_HALEN;		/* Ethernet address size*/
    apkt.arp_plen	= ARP_PALEN;		/* IP address size	*/
    apkt.arp_op	= ARP_OP_RPLY;		/* Type is Reply	*/

    /* Insert local Ethernet and IP address in sender fields	*/

    memcpy(apkt.arp_sndha, NetData.ethucast, ARP_HALEN);
    apkt.arp_sndpa = NetData.ipucast;

    /* Copy target Ethernet and IP addresses from request packet */

    memcpy(apkt.arp_tarha, pktptr->arp_sndha, ARP_HALEN);
    apkt.arp_tarpa = pktptr->arp_sndpa;

    /* Convert ARP packet from host to network byte order */

    arp_hton(&apkt);

    /* Convert the Ethernet header to network byte order */

    eth_hton((struct netpacket *)&apkt);

    /* Send the reply */

    write(ETHER0, (char *)&apkt, sizeof(struct arppacket));
    freebuf((char *)pktptr);
    restore(mask);
    return;
}