ethersim_simport.c 5.01 KB
/*
 * Copyright (C) 1996-1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * 
 * This file is part of the SimOS distribution. 
 * See LICENSE file for terms of the license. 
 *
 */

/*
 * ethersim_simport.c --
 *
 * serviceSimPort 
 *
 *       Service a request that arrives at the simulated ethernet port.
 *
 * Results:
 *      -1 if problem occur with
 *
 * Side effects:
 *
 */
#include "ethersim.h"

int
serviceSimPort(void)
{
    struct  ether_header  *hdrPtr;
    struct sockaddr from;
    int	    fromlen, n;
    int	    etherAddrKey[2];
    int xfersize;
    Hash_Entry *entryPtr;
    HostInfoRecord *srcHostInfo;
    HostInfoRecord *dstHostInfo;

    fromlen = sizeof (from);
    n = recvfrom(simfd, curPacket, sizeof(curPacket), 0, &from, &fromlen);
    if (n < 0) {
	perror("recvfrom");
	return -1;
    }
    if (!validPacket(curPacket, n, &from, fromlen)) {
	return 0;
    }
    if ((n < ETHERMIN + sizeof(struct ether_header)) || 
        (n > ETHERMTU + sizeof(struct ether_header))) {
	fprintf(stderr, "Sim: Bad packet size %d\n", n);
	return 0;
    }

    hdrPtr = (struct ether_header *) curPacket;

    if (verbose) {
	printf("Packet received from UDP host 0x%x\n", 
	       ((struct sockaddr_in *)&from)->sin_addr.s_addr);
	dispEtherPacket(n, hdrPtr, 0);
    }

    /*
     * Ensure that the mapping exists for this ethernet address.
     */
    etherAddrKey[1] = 0;
#ifdef sparc
    bcopy(hdrPtr->ether_shost.ether_addr_octet, (char *) etherAddrKey, 6);
#endif
#ifdef sgi
    bcopy(hdrPtr->ether_shost, (char *) etherAddrKey, 6);
#endif
   
    entryPtr = Hash_CreateEntry(&etheraddrTable, (Address) etherAddrKey, NULL);
    srcHostInfo = (HostInfoRecord *) Hash_GetValue(entryPtr);
    if (srcHostInfo == NULL) {
	srcHostInfo = (HostInfoRecord *) calloc(1, sizeof(HostInfoRecord));
#ifdef sparc 
	bcopy(hdrPtr->ether_shost.ether_addr_octet, &srcHostInfo->etheraddr, 6);
#endif
#ifdef sgi
	bcopy(hdrPtr->ether_shost, &srcHostInfo->etheraddr, 6);
#endif
	Hash_SetValue(entryPtr, srcHostInfo);
    }
    bcopy((caddr_t)&from, (caddr_t)&srcHostInfo->fromaddr, fromlen);
    srcHostInfo->fromlen = fromlen;

#ifdef MACH_NRP
    {
	int offset;
    if ((offset = IsMachNRPPacket(hdrPtr))) {
	xfersize = sendto(nrpfd, curPacket + offset, n-offset, 0x0, 
				(caddr_t) &nrpaddr,
				nrpaddrlen);
	if (xfersize < 0) {
	    perror("sendto nrp");
	}
        return 0;
    }
    }
#endif
    if (htons(hdrPtr->ether_type) == ETHERTYPE_IP ) {
	u_long	inetAddr;
	bcopy(curPacket + sizeof(struct ether_header) + offsetof(struct ip, ip_src),
		(char *) &inetAddr, sizeof(inetAddr));
	if (srcHostInfo->inetAddr != inetAddr) {
	    srcHostInfo->inetAddr = inetAddr;
	    entryPtr = Hash_CreateEntry(&ipaddrTable, (Address)inetAddr,NULL);
	    Hash_SetValue(entryPtr, srcHostInfo);
	}
    }

#ifdef SIM_PROXY
    if ((B(0) == 0xff) && (B(1) == 0xff) && (B(2) == 0xff) &&
	(B(3) == 0xff) && (B(4) == 0xff) && (B(5) == 0xff)) {
#else
    if ((A(0) == 0xff) && (A(1) == 0xff) && (A(2) == 0xff) &&
	(A(3) == 0xff) && (A(4) == 0xff) && (A(5) == 0xff)) {
#endif
	Hash_Search search;
	if(verbose) {
	    printf("Broadcast packet received\n");
	}
	/*
	 * Broadcast. 
	 */
        if (ArpRequest(curPacket, n, curPacket, &n)) {
    		if (n < ETHERMIN + sizeof(struct ether_header)) {
			n =  ETHERMIN + sizeof(struct ether_header);
		}
		goto reply;
        }

	if(verbose) {
	    printf("Non ARP broadcast. sending to:\n");
	}
	for (entryPtr = Hash_EnumFirst(&etheraddrTable, &search); 
	     entryPtr != NULL; entryPtr = Hash_EnumNext(&search)) {
	    dstHostInfo = (HostInfoRecord *) Hash_GetValue(entryPtr);
	    if (dstHostInfo != srcHostInfo) { 
		if(verbose) {
		    printf("  Dest: 0x%x\n");
		}
		xfersize = sendto(simfd, curPacket, n, 0x0, 
				    (struct sockaddr *) &dstHostInfo->fromaddr,
				    dstHostInfo->fromlen);
		if (xfersize < 0) {
		    perror("sendto");
		}
	    }
	}
	return 0;
    } 
  reply:
    etherAddrKey[1] = 0;
#ifdef sparc
    bcopy(hdrPtr->ether_dhost.ether_addr_octet, (char *) etherAddrKey, 6);
#endif
#ifdef sgi
    bcopy(hdrPtr->ether_dhost, (char *) etherAddrKey, 6);
#endif

    entryPtr = Hash_FindEntry(&etheraddrTable, (Address) etherAddrKey);
    if (entryPtr != NULL) {
	dstHostInfo = (HostInfoRecord *) Hash_GetValue(entryPtr);

	xfersize = sendto(simfd, curPacket, n, 0x0, 
				(struct sockaddr *) &dstHostInfo->fromaddr,
				dstHostInfo->fromlen);
	if (xfersize < 0) {
	    perror("sendto");
	}
        return 0;
    } 

    if ((htons(hdrPtr->ether_type) == ETHERTYPE_IP) && (netfd > 0)) {
	u_long	destAddr;
	bcopy(curPacket + sizeof(struct ether_header) + offsetof(struct ip, ip_dst),
		(char *) &destAddr, sizeof(destAddr));
	destAddr = ntohl(destAddr);
	if ((destAddr & mynetmask) != subnetaddr) {
	    outputPacket(curPacket, n);
	} else {
	    if(verbose) {
		printf("Did not forward packet, dest 0x%x, SN 0x%x\n",
		       destAddr, subnetaddr);
	    }
	}
        return 0;
    }

/*
     fprintf(stderr,"Unknown dest address %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x\n", A(0),A(1),A(2),A(3),A(4),A(5),B(0),B(1),B(2),B(3),B(4),B(5));
*/
     return 0;
}