/*
 * Port. This file contains some location hacks for use with 
 *       Asante repeaters.
 *
 * Copyright 1992 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 *
 * Tom Coppeto
 * MIT Network Group
 * 26 August 1992
 *
 *    $Source: /afs/.net.mit.edu/tools/src/port/RCS/address.c,v $
 *    $Author: tom $
 *    $Locker: tom $
 *
 */

#ifndef lint
static char *rcsid = "$Header: /afs/.net.mit.edu/tools/src/port/RCS/address.c,v 1.4 94/01/12 15:00:32 tom Exp Locker: tom $";
#endif

#include "port.h"
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

extern getreq reply;


locate(agents, proto, mac)
     Agent **agents;
     struct in_addr proto;
     char *mac;
{
  objident *o[10];
  caddr_t *dat;

  char *src;
  char macbuf[14];
  unsigned char ipbuf[16];
  unsigned long ip_addr;
  struct hostent *hp;

  char key[100];
  char *note;
  int board;
  int port;
  int age;


  if(!mac)
    ping(proto);

  o[0] = &vNSGroupId;
  o[1] = &vNSPortId;
  o[2] = &vNSSrcMACAddr;
  o[3] = &vNSIPAddr;
  o[4] = &vNSIPTime;
  o[5] = (objident *) NULL;
  
  while(*agents)
    {
      bzero(&(o[0]->cmp[13]), 14 * sizeof(int));
      bzero(&(o[1]->cmp[13]), 14 * sizeof(int));
      bzero(&(o[2]->cmp[13]), 14 * sizeof(int));
      bzero(&(o[3]->cmp[13]), 14 * sizeof(int));
      bzero(&(o[4]->cmp[13]), 14 * sizeof(int));
      
      while(dat = make_lots_o_snmp_nexts(*agents, o))
	{
	  if(oidncmp(o[0], &(reply.varlist.elem[0].name), 13) != 0)
		break;
	  bcopy(dat[0], &board, sizeof(board));
	  bcopy(dat[1], &port, sizeof(port));
          bcopy(dat[3], &age, sizeof(age));
          src = dat[2];
	  
	  sprintf(macbuf, "%02x%02x%02x%02x%02x%02x", 
		  src[0]&0xff, src[1]&0xff, src[2]&0xff, 
		  src[3]&0xff, src[4]&0xff, src[5]&0xff);
	  
	  src = dat[3];
	  sprintf(ipbuf, "%u.%u.%u.%u", src[0]&0xff, src[1]&0xff, 
		  src[2]&0xff, src[3]&0xff);
	  ip_addr = inet_addr(ipbuf);

            if((mac && (!strcasecmp(mac, macbuf) || (*mac == '*'))) || 
	       (!mac && (ip_addr == proto.s_addr)))
  	     {
		  hp = gethostbyaddr(&ip_addr, sizeof(long), AF_INET);
                  strncpy(key, macbuf, 6);
                  key[6] = '\0';
                  note = (char *) get_db(key);
		  
		  printf("%s\t%d/%d\t%s\t%s\t%s\n\t\tage:      %d sec\n\t\thardware: %s\n", 
		 	 (*agents)->name,
			 board, port, macbuf, ipbuf, hp ? hp->h_name : "",
 			 age/100,
			 note ? note : "unknown");
		  
                  sprintf(key, "%s/%d/%d", (*agents)->name, board, port);
                  note = (char *) get_db(key);
		  printf("\t\tlocation: %s\n", note ? note : "unknown");
	    }

	  bcopy(reply.varlist.elem[0].name.cmp, o[0]->cmp, 27 * sizeof(int));
	  bcopy(reply.varlist.elem[1].name.cmp, o[1]->cmp, 27 * sizeof(int));
	  bcopy(reply.varlist.elem[2].name.cmp, o[2]->cmp, 27 * sizeof(int));
	  bcopy(reply.varlist.elem[3].name.cmp, o[3]->cmp, 27 * sizeof(int));
          bcopy(reply.varlist.elem[4].name.cmp, o[4]->cmp, 27 * sizeof(int));
	}
      ++agents;
    }
}



ping(a)
     struct in_addr a;
{
  struct sockaddr_in sin;
  static unsigned char outpack[64];
  struct icmp *icp = (struct icmp *) outpack;
  static struct protoent *proto = (struct protoent *) NULL;
  int s;

  if(!a.s_addr)
    return(0);

  if(!proto && !(proto = getprotobyname("icmp")))
    {
      perror("getprotobyname");
      return;
    }
  
  if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0)
    {
      perror("socket");
      return;
    }
  
  bzero(&sin, sizeof(sin));
  sin.sin_addr = a;
  sin.sin_family = AF_INET;
  sin.sin_port = htons(9); /* discard */

  icp->icmp_type  = ICMP_ECHO;
  icp->icmp_code  = 0;
  icp->icmp_cksum = 0;
  icp->icmp_seq   = 0;
  icp->icmp_id    = 666;

  strcpy(&outpack[8], "porting is fun");
  icp->icmp_cksum = in_cksum(icp, sizeof(outpack));

  sendto(s, outpack, sizeof(outpack), 0, &sin, sizeof(sin));
  (void) close(s);

  return(0);
}


/*
 * Checksum routine for Internet Protocol family headers (C Version)
 */
 
in_cksum(addr, len)
     u_short *addr;
     int len;
{
  register int nleft = len;
  register u_short *w = addr;
  register u_short answer;
  register int sum = 0;
  
  /*
   *  Our algorithm is simple, using a 32 bit accumulator (sum),
   *  we add sequential 16 bit words to it, and at the end, fold
   *  back all the carry bits from the top 16 bits into the lower
   *  16 bits.
   */
   
  while( nleft > 1 )  
    {
      sum   += (int) *w++;
      nleft -= 2;
    }
 
  /* mop up an odd byte, if necessary */
  if( nleft == 1 ) 
    {
      ((u_char *)w)[1] = '\0';
      sum += (int) *w;
    }
  
  /*
   * add back carry outs from top 16 bits to low 16 bits
   */
   
  sum    = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
  sum   += (sum >> 16);                      /* add carry */
  answer = ~sum;                             /* truncate to 16 bits */
  return (answer);
}
 


