/***********************************************************
        Copyright 1996 by Carnegie Mellon University

                      All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of CMU not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.

CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/

#include "defs.h"
#include "config.h"
#include <netinet/in_var.h>
#include <sys/stat.h>  /* for stat() */
#include <sys/types.h>

#include "defaults.h"
#include "snmp.h"
#include "snmplib/asn1.h"
#include "snmplib/party.h"
#include "snmplib/snmp_impl.h"
#include "snmpd/snmp_vars.h"
#include "snmplib/snmp.h"
#include "snmpd/m2m.h" /* for RowStatus values */
#include "bootp.h"
#include "bootpd.h"
#include "dhcpd.h"
#include "dhcp.h"
#include "hash.h"
#include "perm.h"
#include "readfile.h"
#include "dynamic.h"
#include "utils.h"


    u_short dest_port = 0;
    int sdlen = 0;

struct addrCache {
    u_long addr;
    int status;
#define UNUSED 0
#define USED   1
#define OLD 2
};

static struct addrCache addrCache[10];

struct ifreq *   ifconfaddr __P((struct ifconf *ifcp, u_int32 a));
void save_data();

/*
 * Initialize the SNMP part of dhcpd
 */
int /* returns: 0 on success, true on error */
snmp_init(sd)
int *sd;
{
   u_long myaddr;
   int ret;
   struct partyEntry *pp;
   struct sockaddr_in  me;
   int index, portlist[32];

   init_snmp();
   /* init_mib(); why was this here? */
    if (read_party_database("/etc/party.conf") > 0){
   fprintf(stderr, "Couldn't read party database from /etc/party.conf\n");
   exit(0);
    }
    if (read_context_database("/etc/context.conf") > 0){
   fprintf(stderr, "Couldn't read context database from /etc/context.conf\n");
   exit(0);
    }
    if (read_acl_database("/etc/acl.conf") > 0){
   fprintf(stderr, "Couldn't read acl database from /etc/acl.conf\n");
   exit(0);
    }
    if (read_view_database("/etc/view.conf") > 0){
   fprintf(stderr, "Couldn't read view database from /etc/view.conf\n");
   exit(0);
    }

    myaddr = get_myaddr();
    if (ret = agent_party_init(myaddr, ".1.3.6.1")){
   if (ret == 1){
       fprintf(stderr, "Conflict found with initial noAuth/noPriv parties... continuing\n");
   } else if (ret == -1){
       fprintf(stderr, "Error installing initial noAuth/noPriv parties, exiting\n");
       exit(1);
   } else {
       fprintf(stderr, "Unknown error, exiting\n");
       exit(2);
   }
    }

    printf("Opening snmp port(s): ");
    fflush(stdout);
    party_scanInit();
    for(pp = party_scanNext(); pp; pp = party_scanNext()){
   if ((pp->partyTDomain != DOMAINSNMPUDP)
       || bcmp((char *)&myaddr, pp->partyTAddress, 4))
       continue;  /* don't listen for non-local parties */

   dest_port = 0;
   bcopy(pp->partyTAddress + 4, &dest_port, 2);
   for(index = 0; index < sdlen; index++)
       if (dest_port == portlist[index])
      break;
   if (index < sdlen)  /* found a hit before the end of the list */
       continue;
   printf("%u ", dest_port);
   fflush(stdout);
   /* Set up connections */
   *sd = socket(AF_INET, SOCK_DGRAM, 0);
   if (*sd < 0){
       perror("socket");
       return 1;
   }
   me.sin_family = AF_INET;
   me.sin_addr.s_addr = INADDR_ANY;

   /* already in network byte order (I think) */
   me.sin_port = dest_port;
   if (bind(*sd, (struct sockaddr *)&me, sizeof(me)) != 0){
#ifdef ALTERNATE_PORT
       perror("bind");
       me.sin_port = dest_port = 9162;
       printf("%u ", dest_port);
       fflush(stdout);
       if (bind(*sd, (struct sockaddr *)&me, sizeof(me)) != 0){
          perror("bind");
          return 2;
       }
#else
       perror("bind");
       return 2;
#endif
   }

   portlist[sdlen] = dest_port;
   if (++sdlen == 32){
       printf("No more sockets... ignoring rest of file\n");
       break;
   }
    }
    printf("\n");
    bzero((char *)addrCache, sizeof(addrCache));
   return 0;
}

/*
 * Place an IP address into an OID starting at element n
 */
void
put_address(name, addr, n)
   oid	 *name;
   u_long addr;
   int n;
{
   int i;

   for (i=n+3; i>=n+0; i--) {
      name[i] = addr & 0xFF;
      addr >>= 8;
   }
}

/* Get an IP address from an OID starting at element n */
int
get_address(name, length, addr, n)
   oid	 *name;	
   int	  length;
   u_long *addr;
   int n;
{
   int i;
   int ok = 1;

   (*addr) = 0;

   if (length < n+4)
      return 0;

   for (i=n; i<n+4; i++) {
      (*addr) <<= 8;
      if (i >= length)
          ok = 0;
      else
         (*addr) |= name[i];
   }
   return ok;
}

/* sync_timer is called by timer() every TIMER_INTERVAL seconds.
 * Its job is to record this time so that we can compute on demand
 * the approx # seconds remaining until the next timer() call
 */
static time_t lasttimer;

void
sync_timer()
{
    time(&lasttimer);
}

int /* in range [-TIMER_INTERVAL..0] */
secs_remaining_offset()
{
   time_t tm;

   time(&tm);
   return lasttimer-tm;
}

u_char *
var_dhcpstats(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that point
s here */
    register oid    *name;      /* IN/OUT - input name requested, output name fo
und */
    register int    *length;    /* IN/OUT - length of input and output oid's */
    int         exact;      /* IN - TRUE if an exact match was requested. */
    int         *var_len;   /* OUT - length of variable or 0 if function returne
d. */
    int         (**write_method)(); /* OUT - pointer to function to set variable
, otherwise 0 */
{
    oid         newname[MAX_NAME_LEN];
	static int result;

	bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
	newname[11]=0;
    result = compare(name, *length, newname, (int)vp->namelen + 1);
    if ((exact && (result != 0)) || (!exact && (result >= 0)))
		return NULL;
	bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1)* sizeof(oid));
	*length = vp->namelen + 1;
	*write_method = 0;
	*var_len = sizeof(int32);   /* default length */

	switch (vp->magic){
	case DHCPUPTIME:
		result=time(0)-starttime;
		result*=100;
		return (u_char*)&result;
	case DHCPVERSION:
		*var_len=strlen(version);
		return (u_char*)version;
	case DHCPLASTTAB:
		return (u_char*)&modtime;
	case DHCPLASTCONF:
		return (u_char*)&conftime;
	case DHCPNEXTGC:
		return (u_char*)&dhcp_alarm;
	case DHCPDISCOVERS:
		return (u_char*)&discovers_received;
	case DHCPOFFERS:
		return (u_char*)&offers_sent;
	case DHCPREQUESTS:
		return (u_char*)&requests_received;
	case DHCPACKS:
		return (u_char*)&acks_sent;
	case DHCPNACKS:
		return (u_char*)&nacks_sent;
	case DHCPINFORMS:
		return (u_char*)&informs_received;
	case DHCPDECLINES:
		return (u_char*)&declines_received;
	case DHCPRELEASES:
		return (u_char*)&releases_received;
	case DHCPBREQ:
		return (u_char*)&bootp_requests_received;
	case DHCPBRPL:
		return (u_char*)&bootp_replys_sent;
	case DHCPALEASES:
		return (u_char*)&leases;
	case DHCPEXPIRED:
		return (u_char*)&ips_expired;
	case DHCPRECLAIMED:
		return (u_char*)&ips_reclaimed;
	default:
		ERROR("var_dhcpstats, case not implemented");
	}

	return NULL;
}
int
writecommand(action, var_val, var_val_type, var_val_len, statP, name, name_len)
   int      action;
   u_char   *var_val;
   u_char   var_val_type;
   int      var_val_len;
   u_char   *statP;
   oid      *name;
   int      name_len;
{
    int bigsize = 1000;
    u_char  *cp;
    int count, size;
    int32 command;

    if (var_val_type != INTEGER){
    printf("not integer\n");
    return SNMP_ERR_WRONGTYPE;
    }
	bigsize=4;
    asn_parse_int(var_val, &bigsize, &var_val_type, &command, 4);
    if (action == COMMIT){
    switch(command){
      case 1: do_readtab=2;

				
				if(debug>2)
					report(LOG_INFO,"Force readtab via SNMP");
				break;
      case 2: do_readconf=2;
				if(debug>2)
					report(LOG_INFO,"Force read configuration file via SNMP");
				break;
      case 3: do_flush=2;
				if(debug>2)
					report(LOG_INFO,"Force flush to disk via SNMP");
				break;
      case 4: dhcp_alarm=now-1;
				if(debug>2)
					report(LOG_INFO,"Force to garbage collect via SNMP");
				break;
	  default: return SNMP_ERR_BADVALUE;
	}
	}

	return SNMP_ERR_NOERROR;
}

u_char *
var_dhcpconfig(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that point
s here */
    register oid    *name;      /* IN/OUT - input name requested, output name fo
und */
    register int    *length;    /* IN/OUT - length of input and output oid's */
    int         exact;      /* IN - TRUE if an exact match was requested. */
    int         *var_len;   /* OUT - length of variable or 0 if function returne
d. */
    int         (**write_method)(); /* OUT - pointer to function to set variable
, otherwise 0 */
{
    oid         newname[MAX_NAME_LEN];
	int result;
	static unsigned long junk;

	bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
	newname[11]=0;
    result = compare(name, *length, newname, (int)vp->namelen + 1);
    if ((exact && (result != 0)) || (!exact && (result >= 0)))
		return NULL;
	bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1)* sizeof(oid));
	*length = vp->namelen + 1;
	*write_method = 0;
	*var_len = sizeof(int32);   /* default length */

	switch (vp->magic){
	case DHCPCOMMAND:
		*write_method=writecommand;
		junk=0L;
		return (u_char*)&junk;
	case DHCPTABFILE:
		*var_len=strlen(bootptab);
		return (u_char*)bootptab;
	case DHCPCONFFILE:
		*var_len=strlen(conffile);
		return (u_char*)conffile;
	case DHCPGCINTERVAL:
		return (u_char*)&gcinterval;
	case DHCPFINTERVAL:
		return (u_char*)&flush_interval;
	case DHCPFITEMS:
		return (u_char*)&max_cachequeue;
	default:
		ERROR("var_dhcpconfig, case not implemented");
	}

	return NULL;
}

#define INT2OID(I,OIDP) *(OIDP)=((I)>>24)&0xFF; \
 *((OIDP)+1)=((I)>>16)&0xFF;	\
 *((OIDP)+2)=((I)>>8)&0xFF;	\
 *((OIDP)+3)=(I)&0xFF;		

u_char *
var_dhcpbind(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that point
s here */
    register oid    *name;      /* IN/OUT - input name requested, output name fo
und */
    register int    *length;    /* IN/OUT - length of input and output oid's */
    int         exact;      /* IN - TRUE if an exact match was requested. */
    int         *var_len;   /* OUT - length of variable or 0 if function returne
d. */
    int         (**write_method)(); /* OUT - pointer to function to set variable
, otherwise 0 */
{
    oid         newname[MAX_NAME_LEN];
    unsigned long    i;
    int result;
    static char Name[16];
    register char *cp;
	struct host *p;
static 	unsigned long rc;

    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    for(i= 1, p=(struct host*)hash_FirstEntry(boundhshtbl); i<= leases && p; i++,p=(struct host*)hash_NextEntry(boundhshtbl)){
	INT2OID(i,newname+12);
    result = compare(name, *length, newname, (int)vp->namelen + 4);
    if ((exact && (result == 0)) || (!exact && (result < 0)))
        break;
    }
    if (i > leases || !p)
    return NULL;

    bcopy((char *)newname, (char *)name, ((int)vp->namelen + 4) * sizeof(oid));
    *length = vp->namelen + 4;
    *write_method = 0;
    *var_len = sizeof(int32);


    switch (vp->magic){
	case	DHCPCLIID:
		*var_len=p->cl->length;
		return p->cl->data;
	case	DHCPBINDADDR:
		return (u_char*)&p->iaddr.s_addr;
	case	DHCPEXPIRE:
		return (u_char*)&p->expire;
	case	DHCPCODE:
		rc=p->code;
		return (u_char*)&rc;
	default:
		ERROR("var_dhcpbind, case not implemented");
	}

	return NULL;
}

u_char *var_dhcplastbind(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that point
s here */
    register oid    *name;      /* IN/OUT - input name requested, output name fo
und */
    register int    *length;    /* IN/OUT - length of input and output oid's */
    int         exact;      /* IN - TRUE if an exact match was requested. */
    int         *var_len;   /* OUT - length of variable or 0 if function returne
d. */
    int         (**write_method)(); /* OUT - pointer to function to set variable
, otherwise 0 */
{
    oid         newname[MAX_NAME_LEN];
    int i, j, result;
	unsigned long count;
    static struct ifnet ifnet;
    static char Name[16];
    register char *cp;
	unsigned char buf[64];
	struct lastbind *p;

	bzero(newname,sizeof(newname));
    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));


	p=(struct lastbind*)hash_FirstEntry(lastbindhshtbl);
	count=1;
	INT2OID(count,newname+12);
	while(1){
		if(p==NULL)
			return NULL;
		result = compare(name, *length, newname, (int)vp->namelen + 4);
		if ((exact && (result == 0)) || (!exact && (result < 0))){
			if(exact)
				break;
			if(vp->magic!=DHCPVEND && vp->magic!=DHCPCLASS)
				break;
			if(vp->magic==DHCPVEND && p->vend)
				break;
			else if(vp->magic==DHCPCLASS && p->user)
				break;
		}
		count++;
		INT2OID(count,newname+12);
		p=(struct lastbind*)hash_NextEntry(lastbindhshtbl);
	}
		

	if(p==NULL)
		return NULL;
	
    bcopy((char *)newname, (char *)name, 16 * sizeof(oid));
    *length = 16;
    *write_method = 0;
    *var_len = sizeof(int32);


    switch (vp->magic){
	case	DHCPCLIID:
		*var_len=p->cliid->length;
		return (u_char*)p->cliid->data;
	case	DHCPBINDADDR:
		return (u_char*)&p->last_ip.s_addr;
	case	DHCPHWADDR:
		*var_len=p->cliid->length;
		return (u_char*)p->cliidhw->data;
	case	DHCPVEND:
		*var_len=p->vend->length;
		return (u_char*)p->vend->data;
	case	DHCPCLASS:
		*var_len=p->user->length;
		return (u_char*)p->user->data;
	case	DHCPREPLYS:
		return (u_char*)&p->replys;
	case	DHCPLASTTOUCH:
		return (u_char*)&p->last_touch;
	case	DHCPEXPIRE:
		return (u_char*)&p->expire;
	default:
		ERROR("var_dhcpbind, case not implemented");
	}

	return NULL;
}

u_char *
var_dhcpnetwork(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that point
s here */
    register oid    *name;      /* IN/OUT - input name requested, output name fo
und */
    register int    *length;    /* IN/OUT - length of input and output oid's */
    int         exact;      /* IN - TRUE if an exact match was requested. */
    int         *var_len;   /* OUT - length of variable or 0 if function returne
d. */
    int         (**write_method)(); /* OUT - pointer to function to set variable
, otherwise 0 */
{
    oid         newname[MAX_NAME_LEN];
    int i, j, result, count;
    static struct ifnet ifnet;
    static char Name[16];
    register char *cp;
	unsigned char buf[64];
	struct cable *p;
	static unsigned long t;

	bzero(newname,sizeof(newname));
    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));


	p=(struct cable*)hash_FirstEntry(cablehshtbl);
	newname[13]=1;
	while(1){
		if(p==NULL)
			return NULL;
		result = compare(name, *length, newname, (int)vp->namelen + 1);
		if ((exact && (result == 0)) || (!exact && (result < 0)))
			break;
		newname[13]++;
		p=(struct cable*)hash_NextEntry(cablehshtbl);
	}
		

	if(p==NULL)
		return NULL;
	
    bcopy((char *)newname, (char *)name, 14 * sizeof(oid));
    *length = 14;
    *write_method = 0;
    *var_len = sizeof(int32);


    switch (vp->magic){
	case	DHCPNAME:
		*var_len=strlen(p->name->string);
		return (u_char*)p->name->string;
	case	DHCPNETWORK:
		return (u_char*)&p->net;
	case	DHCPMASK:
		return (u_char*)&p->mask;
	case	DHCPDCODE:
		t=0;
		t=(unsigned long)p->code;
		return (u_char*)&t;
	case	DHCPFREE:
		return (u_char*)&p->free;
	default:
		ERROR("var_dhcpbind, case not implemented");
	}

	return NULL;
}

u_char *
var_dhcpunknown(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that point
s here */
    register oid    *name;      /* IN/OUT - input name requested, output name fo
und */
    register int    *length;    /* IN/OUT - length of input and output oid's */
    int         exact;      /* IN - TRUE if an exact match was requested. */
    int         *var_len;   /* OUT - length of variable or 0 if function returne
d. */
    int         (**write_method)(); /* OUT - pointer to function to set variable
, otherwise 0 */
{
    oid         newname[MAX_NAME_LEN];
    unsigned long    i;
    int result;
    static char Name[16];
    register char *cp;
	struct unknownhost *u;
	static unsigned long rc;

    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
	newname[12]=1;
    for(i= 1, u=unknown; i<= num_unknown && u; i++,u=u->next){
	newname[12]=i;
    result = compare(name, *length, newname, (int)vp->namelen + 1);
    if ((exact && (result == 0)) || (!exact && (result < 0)))
        break;
    }
    if (i > num_unknown || !u)
    return NULL;

    bcopy((char *)newname, (char *)name, 13 * sizeof(oid));
    *length = 13;
    *write_method = 0;
    *var_len = sizeof(int32);


    switch (vp->magic){
	case	DHCPUHWADDR:
		*var_len=BP_CHADDR_LEN;
		return u->haddr;
	case	DHCPUHTYPE:
		rc=0xff&u->htype;
		return (u_char*)&rc;
	case	DHCPUHLEN:
		rc=0xff&u->hlen;
		return (u_char*)&rc;
	case	DHCPTIME:
		return (u_char*)&u->last_seen;
	case	DHCPRELAY_AGENT:
		return (u_char*)&u->giaddr;
	case	DHCPFROM_IP_ADDR:
		return (u_char*)&u->from_ip;
	default:
		ERROR("var_dhcpunknown, case not implemented");
	}

	return NULL;
}

int
writecmd(action, var_val, var_val_type, var_val_len, statP, name, name_len)
   int      action;
   u_char   *var_val;
   u_char   var_val_type;
   int      var_val_len;
   u_char   *statP;
   oid      *name;
   int      name_len;
{
	unsigned int ui;
    int count, size;
	struct shared_bindata *cliid;
	struct host *hp;
	struct lastbind *p;
	struct in_addr addr;
	unsigned hashcode;

    if (var_val_type != STRING){
    printf("not string\n");
    return SNMP_ERR_WRONGTYPE;
    }
#define IDOFFSET 11
    if (action == COMMIT){
	if(name[IDOFFSET-1] == 6){
		cliid=(struct shared_bindata*)smalloc(sizeof(struct shared_bindata)
				+(name_len-IDOFFSET)-1);
		cliid->linkcount=1;
		cliid->length=name_len-IDOFFSET;
		for(ui=0;ui<cliid->length;ui++)
			cliid->data[ui]=name[IDOFFSET+ui]&0xff;

		hashcode=hash_HashFunction(cliid->data,cliid->length);
		hp=(struct host*)hash_Lookup(boundhshtbl,hashcode,boundcliidcmp, (hash_datum*)cliid);
		if(hp)
			reuse_addr(hp);
		flush_disk();
		hash_Delete(lastbindhshtbl,hashcode,lastbindcliidcmp,
			(hash_datum*)cliid,free_lastbind);
		hashf_Delete(lastbindpermanent,hashcode,bindfilecmp,
					(hash_datum*)cliid);
		if(!p)
			return SNMP_ERR_BADVALUE;
		
	} else if(name[IDOFFSET-1] == 7){
		if(name_len!=(IDOFFSET+4))
			return SNMP_ERR_NOSUCHNAME;
		((u_char*)&addr.s_addr)[0]=name[IDOFFSET]&0xff;
		((u_char*)&addr.s_addr)[1]=name[IDOFFSET+1]&0xff;
		((u_char*)&addr.s_addr)[2]=name[IDOFFSET+2]&0xff;
		((u_char*)&addr.s_addr)[3]=name[IDOFFSET+3]&0xff;

		hashcode=hash_HashFunction((hash_datum*)&addr,4);
		hp=(struct host*)hash_Lookup(ipboundhshtbl,hashcode,ipcmp, (hash_datum*)&(addr.s_addr));
		if(!hp)
			return SNMP_ERR_BADVALUE;
		reuse_addr(hp);
	}

	}

	return SNMP_ERR_NOERROR;
}
u_char *
var_dhcpcmd(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that point
s here */
    register oid    *name;      /* IN/OUT - input name requested, output name fo
und */
    register int    *length;    /* IN/OUT - length of input and output oid's */
    int         exact;      /* IN - TRUE if an exact match was requested. */
    int         *var_len;   /* OUT - length of variable or 0 if function returne
d. */
    int         (**write_method)(); /* OUT - pointer to function to set variable
, otherwise 0 */
{
    oid         newname[MAX_NAME_LEN];
	unsigned int ui;
    int j, result, count;
    static struct ifnet ifnet;
    static char Name[16];
    register char *cp;
	/* static unsigned char buf[1000]; */
	static unsigned char buf[LASTBIND_FLAT_MAXLEN];
	int buflen;
	unsigned long t;
	struct shared_bindata *cliid;
	unsigned hashcode;
	struct host *hp;
	struct lastbind *p;
	struct in_addr addr;

	*write_method=writecmd;
	p=NULL;
	if(!exact)
		return NULL;
#define IDOFFSET 11
	if(vp->magic == DHCPCMDCLIID){
		cliid=(struct shared_bindata*)smalloc(sizeof(struct shared_bindata)
				+(*length-IDOFFSET)-1);
		cliid->linkcount=1;
		cliid->length=*length-IDOFFSET;
		for(ui=0;ui<cliid->length;ui++)
			cliid->data[ui]=name[IDOFFSET+ui]&0xff;
		
		hashcode=hash_HashFunction(cliid->data,cliid->length);

		p=(struct lastbind*)hash_Lookup(lastbindhshtbl,hashcode, lastbindcliidcmp,(hash_datum*)cliid);
		if(!p)
			return NULL;

		buflen=bind2data(p,buf,sizeof(buf));
		
		*var_len=buflen;
		return buf;
	} else if (vp->magic == DHCPCMDIP){
		if(*length!=(IDOFFSET+4))
			return NULL;
		((u_char*)&addr.s_addr)[0]=name[IDOFFSET]&0xff;
		((u_char*)&addr.s_addr)[1]=name[IDOFFSET+1]&0xff;
		((u_char*)&addr.s_addr)[2]=name[IDOFFSET+2]&0xff;
		((u_char*)&addr.s_addr)[3]=name[IDOFFSET+3]&0xff;

		hashcode=hash_HashFunction((hash_datum*)&addr,4);
		hp=(struct host*)hash_Lookup(ipboundhshtbl,hashcode,ipcmp, (hash_datum*)&(addr.s_addr));
		if(hp){
			hashcode=hash_HashFunction(hp->cl->data,hp->cl->length);
			p=(struct lastbind*)hash_Lookup(lastbindhshtbl,hashcode, lastbindcliidcmp,(hash_datum*)hp->cl);
		} else {
			hp=(struct host*)hash_Lookup(iphashtable,hashcode,ipcmp,(hash_datum*)&(addr.s_addr));
			if(!hp || !hp->flags.cliid)
				return NULL;
			hashcode=hash_HashFunction(hp->cliid->data,hp->cliid->length);
			p=(struct lastbind*)hash_Lookup(lastbindhshtbl,hashcode,lastbindcliidcmp,(hash_datum*)hp->cliid);
		}
		if(!p)
			return NULL;
		
		*var_len=bind2data(p,buf,sizeof(buf));
		return buf;
	}

	return NULL;

}
