/*     
 * ip_control.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Revision: 1.2 $
 * $Date: 1996/02/01 15:33:00 $
 */

#include "xkernel.h"
#include "ip.h"
#include "ip_i.h"
#include "route.h"


#define IPHOSTLEN	sizeof(IPhost)


/*
 * ip_controlsessn
 */
int
ipControlSessn(s, opcode, buf, len)
    Sessn s;
    int opcode;
    char *buf;
    int len;
{
    SState        *sstate;
    PState        *pstate;
    IPheader      *hdr;
    
    xAssert(xIsSessn(s));
    sstate = (SState *)s->state;
    pstate = (PState *)s->myprotl->state;
    
    hdr = &(sstate->hdr);
    switch (opcode) {
	
      case GETMYHOST :
	checkLen(len, IPHOSTLEN);
	*(IPhost *)buf = sstate->hdr.source;
	return IPHOSTLEN;
	
      case GETPEERHOST :
	checkLen(len, IPHOSTLEN);
	*(IPhost *)buf = sstate->hdr.dest;  
	return IPHOSTLEN;
	
      case GETMYHOSTCOUNT:
      case GETPEERHOSTCOUNT:
	checkLen(len, sizeof(int));
	*(int *)buf = 1;
	return sizeof(int);

      case GETMYPROTO :
      case GETPEERPROTO :
	checkLen(len, sizeof(long));
	*(long *)buf = sstate->hdr.prot;
	return sizeof(long);
	
      case GETMAXPACKET :
	checkLen(len, sizeof(int));
	*(int *)buf = IPMAXPACKET;
	return sizeof(int);
	
      case GETOPTPACKET :
	checkLen(len, sizeof(int));
	*(int *)buf = sstate->mtu - IPHLEN;
	return sizeof(int);
	
      case IP_REDIRECT:
	return ipControlProtl(s->myprotl, opcode, buf, len);
	
      case IP_GETPSEUDOHDR:
        {
            IPpseudoHdr *phdr = (IPpseudoHdr *)buf;

            checkLen(len, sizeof(IPpseudoHdr));
            phdr->src = sstate->hdr.source;
            phdr->dst = sstate->hdr.dest;
            phdr->zero = 0;
            phdr->len = 0;
            phdr->prot = sstate->hdr.prot;
            return sizeof(IPpseudoHdr);
        }

      default : 
	xTrace0(ipp,3,"Unrecognized opcode -- forwarding");
	return xControlSessn(xGetSessnDown(s, 0), opcode, buf, len);
    }
}

Part *
ipGetParticipants(s)
Sessn s;
{
    Part   *p;
    SState *sstate = (SState *)s->state;

    /* 
     * Since we completely rewrite the participant when we open the lower
     * session, we'll just construct the participants
     */
    p = (Part *)xMalloc(2 * sizeof(Part));
    partInit(p, 2);
    /* remote host */
    partPush(p[0], &sstate->hdr.dest, sizeof(IPhost));
    /* local host */
    partPush(p[1], &sstate->hdr.source, sizeof(IPhost));
    return p;
}

/*
 * ip_controlprotl
 */
int
ipControlProtl(self, opcode, buf, len)
    Protl self;
    int opcode;
    char *buf;
    int len;
{
    PState	*pstate;
    IPhost 	net, mask, gw, dest;
    route 	*rt;
    
    xAssert(xIsProtl(self));
    pstate = (PState *) self->state;
    
    switch (opcode) {
	
      case IP_REDIRECT :
	{
	    checkLen(len, 2*IPHOSTLEN);
	    net = *(IPhost *)buf;
	    netMaskFind(&mask, &net);
	    gw = *(IPhost *)(buf + IPHOSTLEN);
	    xTrace3(ipp, 4, "IP_REDIRECT : net = %s, mask = %s, gw = %s",
		    ipHostStr(&net), ipHostStr(&mask), ipHostStr(&gw));
	    /*
	     * find which interface reaches the gateway
	     */
	    rt_add(pstate, &net, &mask, &gw, -1, RTDEFAULTTTL);
	    return 0;
	}

	/* test control ops - remove later */
      case IP_GETRTINFO :
	/* get route info for a given dest address :
	   in : IP host address 
	   out : route structure for this address
	   */
	checkLen(len, sizeof(route));
	dest = *(IPhost *)buf;
	rt = rt_get(pstate, &dest);
	*(route *)buf = *rt;
	rt_free(pstate, rt);
	return (sizeof(route));

      default:
	xTrace0(ipp,3,"Unrecognized opcode");
	return xControlProtl(xGetProtlDown(self, 0), opcode, buf, len);
    }
}
