/*
 *------------------------------------------------------------------
 *
 * $Source: /mit/cgw/src/tftp.mar/RCS/ether.c,v $
 * $Revision: 1.10 $
 * $Date: 89/05/23 16:15:00 $
 * $State: Exp $
 * $Author: mar $
 * $Locker:  $
 *
 * $Log:	ether.c,v $
 * Revision 1.10  89/05/23  16:15:00  mar
 * clean up printed messages
 * 
 * Revision 1.9  89/04/04  14:32:55  mar
 * fixed broken dump naming
 * 
 * Revision 1.8  89/03/29  17:39:44  probe
 * Renamed dump() to hex_dump() so as not to conflict with libsa.a on ibm032
 * 
 * Revision 1.7  89/03/19  12:42:35  probe
 * Fixed "un" declaration...
 * 
 * Revision 1.6  89/03/18  09:30:53  probe
 * Fixed an error in the definition of dump().
 * 
 * Revision 1.5  89/03/18  09:07:01  probe
 * Added support for the "un" driver for the ibm032.
 * 
 * Revision 1.4  89/03/15  18:46:53  mar
 * removed some old debugging stuff #ifdef'ed out;
 * interrupt handler installation changed (jon)
 * handle DEQNA & VS2000 se ethernets
 * shorten retransmit time for ARP requests
 * 
 * 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.10 89/05/23 16:15:00 mar Exp $";
#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	*/ \
		}

unsigned char etmyaddr[6];
unsigned char etbroad[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

#ifdef standalone

#  ifdef vax
ext void qna_in_up(), qna_out_up(), qna_out(), qna_dev_read();
dct qnadct[2] = {
    DCTMAC(0, qna_in_up, qna_dev_read, 0x20001920, 0x3f8, &qnadct[1]),
    DCTMAC(0, qna_out_up, qna_out, 0x20001920, 0x3fc, &qnadct[0]),
};
ext void se_in_up(), se_out(), se_dev_read();
dct sedct[2] = {
    DCTMAC(0, se_in_up, se_dev_read, 0, 0, &sedct[1]),
    DCTMAC(0, 0, se_out, 0, 0, &sedct[0]),
};
extern int cpu, sid_ext;
#  endif vax
#  ifdef ibm032
ext void un_in_up(), un_out(), un_dev_read();
dct undct[2] = {
    DCTMAC(0, un_in_up, un_dev_read, 0, 0, &undct[1]),
    DCTMAC(0, 0, un_out, 0, 0, &undct[0]),
};
#  endif ibm032

#else standalone

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]),
};

#endif

dct *ether_in, *ether_out;

unsigned char *et_init() 
{
  int i;

#ifdef vax
  if (cpu == 8 && sid_ext == 4) {
      ether_in = &sedct[0];
      ether_out = &sedct[1];
  } else {
      ether_in = &qnadct[0];
      ether_out = &qnadct[1];
  }
#endif vax
#ifdef ibm032
  ether_in = &undct[0];
  ether_out = &undct[1];
#endif ibm032
  
  init_dev (ether_in);
  init_dev (ether_out);

  puts ("Ethernet address: ");
  print_ether_addr (etmyaddr);

  return (etmyaddr);
}

int et_read(data, max_size)
char *data;
int max_size;
{
    register int cc; 
  
    cc = dev_read (ether_in, 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 (ether_out, 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 = 50; 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");
}

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

	printf("\n");
}
