
/*
    IPX support library - RIP

    Copyright (C) 1994, 1995  Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "ipxrip.h"

RipPacket* ipx_rip_alloc(int n)
{
  if (n>IPX_RIP_MAX_ENTRIES) return NULL;
  return (RipPacket*)malloc(ipx_rip_size(n));
}

int ipx_rip_size(int n)
{
  if (n>IPX_RIP_MAX_ENTRIES) return 0;
  return sizeof(RipPacket)+(n-1)*sizeof(RipEntry);
}

static void ipx_rip_sendto(void* buffer,int size,struct sockaddr_ipx* daddr)
{ 
  if (ipx_rip_output_func!=NULL) ipx_rip_output_func(buffer,size,daddr);
}

int ipx_rip_output_rip_output(RipOutput* out,IPXNet iface)
{
	out->entries=0;
	out->buffer=ipx_rip_alloc(IPX_RIP_MAX_ENTRIES);
	if (out->buffer==NULL) return 0;
	out->buffer->operation=htons(IPX_RIP_OP_REQUEST);
	out->dest_addr.sipx_family=AF_IPX;
	out->dest_addr.sipx_type=IPX_RIP_PTYPE;
	out->dest_addr.sipx_network=iface;
	return 1;
}

void ipx_rip_output_flush(RipOutput* out)
{
	if (out->entries==0) return;
	ipx_rip_sendto(out->buffer,ipx_rip_size(out->entries),&(out->dest_addr));
	out->entries=0;
}

void ipx_rip_output_request(RipOutput* out,IPXNet net)
{
	RipEntry* re;
	if (out->entries>=IPX_RIP_MAX_ENTRIES)
		ipx_rip_output_flush(out);
	if (out->buffer->operation!=htons(IPX_RIP_OP_REQUEST))
	{
		ipx_rip_output_flush(out);
		out->buffer->operation=htons(IPX_RIP_OP_REQUEST);
	}
	re=out->buffer->rip_entries+out->entries;
	re->network=net;
	re->hops=0;
	re->ticks=0;
	out->entries++;
}

void ipx_rip_output_response(RipOutput* out,IPXNet net,hop_t hops,tick_t ticks,int down_allow)
{
	RipEntry* re;
	if (hops>=IPX_RIP_NET_DOWN && !down_allow) return;
	if (out->entries>=IPX_RIP_MAX_ENTRIES)
		ipx_rip_output_flush(out);
	if (out->buffer->operation!=htons(IPX_RIP_OP_RESPONSE))
	{
		ipx_rip_output_flush(out);
		out->buffer->operation=htons(IPX_RIP_OP_RESPONSE);
	}
	re=out->buffer->rip_entries+out->entries;
	re->network=net;
	re->hops=htons(hops);
	re->ticks=htons(ticks);
	out->entries++;
}

void ipx_rip_output_set_destination(RipOutput* out,IPXNode node,IPXPort port)
{
	ipx_rip_output_flush(out);
	ipx_assign_node(out->dest_addr.sipx_node,node);
	out->dest_addr.sipx_port=htons(port);
}

void ipx_rip_dump(RipPacket* pkt,int len)
{
	ipx_rip_fdump(stdout,pkt,len);
}

void ipx_rip_fdump(FILE* file,RipPacket* pkt,int len)
{
  RipEntry* re=pkt->rip_entries;
  int ent=(len-2)/8;
  if (len<2) return;
  fprintf(file,"Operation: %i size: %i ",ntohs(pkt->operation),len);
  switch (ntohs(pkt->operation))
  {
    case IPX_RIP_OP_REQUEST:
      fprintf(file,"(Request)\n");
      if (ent*8+2!=len) 
      {
        fprintf(file,"Warning: Bad RIP size (not 8*n+2)\n");
      }
      for(;ent--;re++)
      {
        fprintf(file,"RIP: Network: ");
        ipx_fprint_network(file,re->network);
        fprintf(file,"\n");
      }
      break;
    case IPX_RIP_OP_RESPONSE:
      fprintf(file,"(Response)\n");
      if (ent*8+2!=len) 
      {
        fprintf(file,"Warning: Bad RIP size (not 8*n+2)\n");
      }
      for(;ent--;re++)
      {
        fprintf(file,"RIP: Network: ");
        ipx_fprint_network(file,re->network);
        fprintf(file," HopCount: %u Ticks: %u\n",
                ntohs(re->hops),ntohs(re->ticks));
      }
      break;
    default:
      fprintf(file,"(Unknown)\n");
      break;
  }
}

void (*ipx_rip_output_func)(void*,int,struct sockaddr_ipx*)=NULL;

