/*
 *------------------------------------------------------------------
 *
 * $Source: /mit/cgw/src/tftp.vax/RCS/ether.c,v $
 * $Revision: 1.3 $
 * $Date: 88/07/11 19:07:39 $
 * $State: Exp $
 * $Author: jon $
 * $Locker: jon $
 *
 * $Log:	ether.c,v $
 * Revision 1.3  88/07/11  19:07:39  jon
 * Sommerfeld's changes.
 * 
 * 
 *------------------------------------------------------------------
 */

#ifndef lint
static char *rcsid_ether_c = "$Header: ether.c,v 1.3 88/07/11 19:07:39 jon Locked $";
#endif	lint

#include "ether.h"
#include <types.h>
#include <sys.h>

/* The interrupt vector points into the DCT.  This code is what is
 * found.  It pushes the address of the DCT onto the stack and calls a
 * standard interrupt handler, md_inth.  This interrupt handler saves
 * all the registers and then calls the C routine specified by the DCT
 * in d_iha with the address of the DCT as its argument.
 */
#define	MD_IHD	{ \
		0xefdf,	0xfffa, 0xffff,	/*	pushal -6(pc)	*/ \
		0x9f17, md_inth		/*	jmp md_inth	*/ \
		}

/* This macro sets an interrupt vector.  It is a macro so that if some
 * machine needs something more complicated, it can easily be turned
 * into an assembly language routine.
 */

#ifdef ndef
ext word scb[];
#define	set_int(i_vec, addr)	scb[((word)i_vec)/sizeof(word)] = (word)(addr);
#endif

unsigned char etmyaddr[6];
#ifdef ndef
unsigned char etbroad[6] = { 0x08, 0x00, 0x2b, 0x05, 0xd4, 0x47 };
#else
unsigned char etbroad[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#endif

ext void qna_in_up(), qna_out_up(), qna_out(), qna_in(), qna_int();
dct qnadct[2] = {
    DCTMAC(qna_int, qna_in_up, qna_in, 0x20001920, 0x3f8, &qnadct[1]),
    DCTMAC(qna_int, qna_out_up, qna_out, 0x20001920, 0x3fc, &qnadct[0]),
};

unsigned char *et_init() 
{
  int i;

  init_dev (&qnadct[0]);
  init_dev (&qnadct[1]);

  puts ("ethernet address: ");
  print_ether_addr (etmyaddr);
  puts ("\n");

  return (etmyaddr);
}

int et_read(data, max_size)
	char *data;
	int max_size;
{
	register int cc; 
  
  cc = dev_read (&qnadct[0], data, max_size);
#ifdef ETHER_DEBUG
  if (cc != 0) {
    puts ("read: ");
    dump_ether_header (data);
  }
#endif
	return (cc);
}

int et_write(data, len)
	char *data;
	int len;
{

#ifdef ETHER_DEBUG
  puts ("writing: ");
  dump_ether_header (data);
#endif
  dev_write (&qnadct[1], data, len);
}

/* Send an address request packet for internet address ipaddr. */

static long cachip = 0;
static char cachet[6];
static char buffer[500];

ipadcpy(s,d)
  unsigned char d[], s[];
{ int i; 
  for (i = 0; i < 4; i++) (d)[i] = (s)[i];
}

et_arp(ipaddr, eth)
	long ipaddr;
	char *eth;
{
  struct adr adr;
  struct adr *padr2 = (struct adr *)buffer;
  int i, cc;

  if(cachip == ipaddr) {
    etadcpy(cachet, eth);
    return;
  }

  etadcpy(etbroad, adr.ar_et.et_dst);
  etadcpy(etmyaddr, adr.ar_et.et_src);
#ifdef DEBUG
  puts ("ARP: etmyaddr = "); print_ether_addr(etmyaddr); puts ("\n");
#endif
#ifdef DEBUG
  puts ("ARP: etbroad = "); print_ether_addr(etbroad); puts ("\n");
#endif
  adr.ar_et.et_type = ETHER_ARP;
  adr.ar_hd = ETHER_HTYPE;
  adr.ar_pro = ETHER_IP;
  adr.ar_hln = ETHER_HLEN;
  adr.ar_pln = 4;
  adr.ar_op  = ARP_REQ;
  etadcpy(etmyaddr, adr.ar_sha);
  ipadcpy (&in_me, adr.ar_spa);
  ipadcpy (&ipaddr, adr.ar_tpa);

  for (;;) {
    et_write(adr.ar_et.et_dst, sizeof (struct adr) -2 /* pad at start */);
    for (i = 65535; i > 0; i--) {
      cc = et_read (padr2->ar_et.et_dst, sizeof (buffer));
      if (cc == 0) continue;
      if (padr2->ar_et.et_type != ETHER_ARP) continue;
      if (padr2->ar_op != ARP_REP) continue;
      /* Got it! */
#ifdef DEBUG
      puts ("ARP reply from ");
      print_ether_addr (padr2->ar_sha);
      puts ("\n");
#endif
      etadcpy(padr2->ar_sha, cachet);
      etadcpy(cachet, eth);
      cachip = ipaddr;
      return;
    }
  }
}
	

print_ether_addr (e)
     char *e;
{
  int i;

  for (i=0; i < 5; i++) {
    phex_byte (e[i]);
    puts (":");
  }
  phex_byte(e[5]);
  puts (" ");
}

dump_ether_header(buf)
     char *buf;
{
  struct et_real_hdr *e;

  e = (struct et_real_hdr *) buf;
  puts ("dst: ");
  print_ether_addr (e->et_dst);
  puts (" src: ");
  print_ether_addr (e->et_src);
  puts (" typ: ");
  phex (e->et_type);
  puts ("\n");
}

dump(p,l)
	char *p; {
	int i,j,l;
	
	for(i=1; i< l; i++) {
		printf("%02x ", *p++&0xff);
		for(j=0; j<500; j++) ;
		if(i%16 == 0) printf("\n");
	}

	printf("\n");
	}
