ethersim_init.c 8.65 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_init.c -- 
 * 
 * initSNPdevice --
 *
 * Initialize the snoop file descriptor so that
 * we can catch IP packets for this subnet.
 * Result: Return the file descriptor is successful.
 *         Otherwise, return -1.
 *
 */
#include "ethersim.h"

#ifdef sgi
/* char *device;            Network interface name. */
/* u_long *subNetAddr;      IP addresses (or address) for which proxy should be done */
/* u_long count;            number of IP addresses */
/* u_long netmask;          Network address mask of the interface.*/
int
#ifdef SIM_PROXY
initSNPdevice(char *device, u_long *subNetAddr, u_long count, u_long netmask)
#else
initSNPdevice(char *device, u_long subNetAddr, u_long netmask)
#endif
{
    int s, i;
    struct sockaddr_raw sr;
    struct snoopfilter sf;
    struct ether_ip_header *ptr;
    int cc = 60000, on = 1;

    /*
     * Ethernet address of gateway machine(e.g. paia ).
     */
    myetheraddr[0] = 8;
    myetheraddr[1] = 0;
    myetheraddr[2] = 0x69;
    myetheraddr[3] = 2;
    myetheraddr[4] = 0x14;
    myetheraddr[5] = 0xf1;

    /*
     * Create a raw socket for snoop device.
     */
    s = socket(PF_RAW,SOCK_RAW,RAWPROTO_SNOOP);
    if ( s < 0) {
        perror("initSNPdevice:socket");
        return -1;
    }

   /*
    * Bind the raw socket to the network interface.
    */
    sr.sr_family = AF_RAW;
    sr.sr_port = 0;
    strncpy(sr.sr_ifname,device,sizeof(sr.sr_ifname));
    if ( bind(s,&sr,sizeof(sr)) < 0) {
        perror("initSNPdevice:bind");
        goto bad;
    }

#ifdef SIM_PROXY
    if ( !((netmask == 0xff000000) || (netmask == 0xffff0000) ||
           (netmask == 0xffffff00) || (netmask == 0xffffffff))) {
       fprintf(stderr,"Code can't handle netmask of 0x%x\n",netmask);
       goto bad;
    }
#else
    if ( !((netmask == 0xff000000) || (netmask == 0xffff0000) ||
           (netmask == 0xffffff00))) {
       fprintf(stderr,"Code can't handle netmask of 0x%x\n",netmask);
       goto bad;
    }
#endif

#ifdef SIM_PROXY
    for(i=0; i<count; i++) {
#endif
    /*
     * Initialize a filter to only return IP packets to the
     * specified network. Add it to the interface's filter set.
     */
    bzero((char*)&sf,sizeof(sf));

    /*
     * Set the filter mask and matching value to only accept IP packets.
     */
    ptr = (struct ether_ip_header *) RAW_HDR(sf.sf_mask,struct ether_header);
    ptr->etherHdr.ether_type = 0xffff;
    ptr = (struct ether_ip_header *) RAW_HDR(sf.sf_match,struct ether_header);
    ptr->etherHdr.ether_type = htons(ETHERTYPE_IP);

    /* 
     * Set the filter to only accept packets sent to this network.
     */
    {
        struct in_addr netval;
        struct in_addr srcNetVal;

        netval.s_addr = htonl(netmask);
        ptr = (struct ether_ip_header*) RAW_HDR(sf.sf_mask,struct ether_header);
        bcopy((u_char*) &netval,(u_char*) (u_char*) &sf + 32,4);
#ifdef SIM_PROXY
        netval.s_addr  = subNetAddr[i] & netmask ;
#else
        netval.s_addr  = htonl(((u_long)subNetAddr) & netmask );
#endif
        ptr= (struct ether_ip_header *)RAW_HDR(sf.sf_match,struct ether_header);
        bcopy((u_char*) &netval,(u_char*) (u_char*) &sf + 36+ 32,4);
    }

    if ( ioctl(s,SIOCADDSNOOP,&sf) < 0) {
        perror("initSNPdevice:SIOCADDSNOOP");
        goto bad;
    }
#ifdef SIM_PROXY
    }
#endif

    /*
     * Increase the socket's receive buffer size to a generous upper
     * bound, to cope with promiscuous reception of heavy traffic.
     * Turn snooping on and read captured packets.
     */
     if ( setsockopt(s,SOL_SOCKET,SO_RCVBUF,(char *)&cc, sizeof(cc))< 0){
        perror("initSNPdevice:setsockopt");
        goto bad;
     }
     if ( ioctl(s,SIOCSNOOPING,&on) < 0) {
        perror("initSNPdevice:SIOSNOOPING");
        goto bad;
     }

     return s;

 bad:
    (void)close(s);
    return -1;
}
#endif    /* sgi */


#ifdef sparc 
int 
initNITdevice(device, subNetAddr, netmask)
    char	    *device;    /* Network interface name. */
    u_long 	   subNetAddr;  /* IP address of the subnet. */
    u_long	   netmask;	/* Network address mask of the interface. */
{
      struct strioctl     si;
      struct ifreq   ifr;
      struct packetfilt pf;
      int   err, cmd;
      int snaplen;
      int fd;

      fd = open(NIT_DEV, O_RDWR, 0);
      if (fd < 0) {
	  perror("open of NIT_DEV");
	  return -1;
      }

      /* Arrange to get discrete messages from the stream. */
      err = ioctl(fd, I_SRDOPT, (char *)RMSGD);
      if (err < 0) {
	  perror("I_SRDOPT RMSGD");
	  goto bad;
      }


      /* Configure the nit device, binding it to the proper
	 underlying interface and setting the snapshot length to
	 include entire ethernet packets. */
      strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
      ifr.ifr_name[sizeof ifr.ifr_name - 1] = '\0';
      si.ic_cmd = NIOCBIND;
      si.ic_timout = INFTIM;
      si.ic_len = sizeof ifr;
      si.ic_dp = (char *)&ifr;

      err = ioctl(fd, I_STR, (char *)&si);
      if (err < 0) {
	  perror("I_STR NIOCBIND");
	  goto bad;
      }

      snaplen = 0;
      si.ic_cmd = NIOCSSNAP;
      si.ic_timout = INFTIM;
      si.ic_len = sizeof snaplen;
      si.ic_dp = (char *)&snaplen;
      err = ioctl(fd, I_STR, (char *)&si);
      if (err < 0) {
	  perror("I_STR NIOCSSNAP");
	  goto bad;
      }
      /*
       * Read out the ethernet address so we can fill them into packets
       * being sent.
       */
      si.ic_cmd = SIOCGIFADDR;
      si.ic_timout = INFTIM;
      si.ic_len = sizeof ifr;
      si.ic_dp = (char *)&ifr;
      err = ioctl(fd, I_STR, (char *)&si);
      if (err < 0) {
	  perror("I_STR SIOCGIFADDR");
	  goto bad;
      }
      bcopy(ifr.ifr_addr.sa_data, (char *) &myetheraddr, sizeof(myetheraddr));

      if (!((netmask == 0xff000000) || (netmask == 0xffff0000) || 
            (netmask == 0xffffff00))) {
	  fprintf(stderr, "Code can't handle netmask of 0x%x\n", netmask);
	  goto bad;
      }


      /*
       * Add the packet filter to only return IP packets to the specified
       * network. 
       */

      err = ioctl(fd, I_PUSH, "pf");
      if (err < 0) {
	  perror("I_PUSH pf");
	  exit(1);
      }
      cmd = 0;
      pf.Pf_Filter[cmd++] = ENF_PUSHWORD + (u_short)
		 offsetof(struct ether_header, ether_type)/sizeof(u_short);
      pf.Pf_Filter[cmd++] = ENF_PUSHLIT | ENF_CAND;
      pf.Pf_Filter[cmd++] = htons(ETHERTYPE_IP);

      if (netmask == 0xff000000) {
	  u_short lowval, highval;
	  lowval = (((u_long)subNetAddr) & netmask) >> 16;
	  highval = lowval | 0xff;
	  pf.Pf_Filter[cmd++] = ENF_PUSHWORD + (u_short) 
		      sizeof(struct ether_header)/sizeof(u_short) +
		       offsetof(struct ip, ip_dst)/sizeof(u_short);
	  pf.Pf_Filter[cmd++] = ENF_PUSHLIT | ENF_GE;
          pf.Pf_Filter[cmd++] = lowval;
	  pf.Pf_Filter[cmd++] = ENF_PUSHWORD + (u_short) 
		      sizeof(struct ether_header)/sizeof(u_short) +
		       offsetof(struct ip, ip_dst)/sizeof(u_short);
	  pf.Pf_Filter[cmd++] = ENF_PUSHLIT | ENF_LE;
          pf.Pf_Filter[cmd++] = highval;
	  pf.Pf_Filter[cmd++] = ENF_AND;
      } else {
	  pf.Pf_Filter[cmd++] = ENF_PUSHWORD + (u_short) 
		      sizeof(struct ether_header)/sizeof(u_short) +
		       offsetof(struct ip, ip_dst)/sizeof(u_short);
	  pf.Pf_Filter[cmd++] = ENF_PUSHLIT | ENF_EQ;
          pf.Pf_Filter[cmd++] = (((u_long)subNetAddr) & netmask) >> 16;
	  if (netmask == 0xffffff00) {
	      u_short lowval, highval;
	      lowval = (((u_long)subNetAddr) & netmask) & 0xffff;
	      highval = lowval | 0xff;
	      pf.Pf_Filter[cmd++] = ENF_PUSHWORD + (u_short) 
			  sizeof(struct ether_header)/sizeof(u_short) +
			   offsetof(struct ip, ip_dst)/sizeof(u_short) + 1;
	      pf.Pf_Filter[cmd++] = ENF_PUSHLIT | ENF_GE;
	      pf.Pf_Filter[cmd++] = lowval;
	      pf.Pf_Filter[cmd++] = ENF_PUSHWORD + (u_short) 
			  sizeof(struct ether_header)/sizeof(u_short) +
			   offsetof(struct ip, ip_dst)/sizeof(u_short) + 1;
	      pf.Pf_Filter[cmd++] = ENF_PUSHLIT | ENF_LE;
	      pf.Pf_Filter[cmd++] = highval;
	      pf.Pf_Filter[cmd++] = ENF_AND;
	  }
      }
      pf.Pf_FilterLen = cmd;


      si.ic_cmd = NIOCSETF;
      si.ic_timout = INFTIM;
      si.ic_len = sizeof pf;
      si.ic_dp = (char *)&pf;
      err = ioctl(fd, I_STR, (char *)&si);
      if (err < 0) {
	  perror("I_STR NIOCSETF");
	  goto bad;
      }

      /* Flush the read queue, to get rid of anything that accumulated
	 before the device reached its final configuration. */
      err = ioctl(fd, I_FLUSH, (char *)FLUSHR);
      if (err < 0) {
	  perror("I_STR FLUSHR");
	  goto bad;
      }
      return fd;
  bad:
      (void) close(fd);
      return -1;
}
#endif  /* sparc */