Net2/usr/src/contrib/isode/snmp/syntax.c

/* syntax.c - SMI syntax handling */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/snmp/RCS/syntax.c,v 7.19 91/02/22 09:44:38 mrose Interim $";
#endif

/* 
 * $Header: /f/osi/snmp/RCS/syntax.c,v 7.19 91/02/22 09:44:38 mrose Interim $
 *
 * Contributed by NYSERNet Inc.  This work was partially supported by the
 * U.S. Defense Advanced Research Projects Agency and the Rome Air Development
 * Center of the U.S. Air Force Systems Command under contract number
 * F30602-88-C-0016.
 *
 *
 * $Log:	syntax.c,v $
 * Revision 7.19  91/02/22  09:44:38  mrose
 * Interim 6.8
 * 
 * Revision 7.18  91/01/13  11:05:45  mrose
 * update
 * 
 * Revision 7.17  91/01/12  21:22:58  mrose
 * update
 * 
 * Revision 7.16  91/01/11  15:35:36  mrose
 * sets
 * 
 * Revision 7.15  90/12/18  10:14:07  mrose
 * update
 * 
 * Revision 7.14  90/11/20  15:32:55  mrose
 * update
 * 
 * Revision 7.13  90/11/04  19:16:36  mrose
 * update
 * 
 * Revision 7.12  90/10/29  18:39:12  mrose
 * updates
 * 
 * Revision 7.11  90/10/23  20:37:17  mrose
 * update
 * 
 * Revision 7.10  90/08/18  00:44:42  mrose
 * touch-up
 * 
 * Revision 7.9  90/08/08  14:01:39  mrose
 * stuff
 * 
 * Revision 7.8  90/07/09  14:49:41  mrose
 * sync
 * 
 * Revision 7.7  90/04/18  08:52:03  mrose
 * oid_normalize
 * 
 * Revision 7.6  90/04/08  03:23:20  mrose
 * touch-up
 * 
 * Revision 7.5  90/03/23  17:27:35  mrose
 * update
 * 
 * Revision 7.4  90/03/08  08:05:25  mrose
 * touch-up
 * 
 * Revision 7.3  90/02/19  19:23:14  mrose
 * again
 * 
 * Revision 7.2  90/02/19  19:17:11  mrose
 * again
 * 
 * Revision 7.1  90/01/11  18:34:48  mrose
 * real-sync
 * 
 * Revision 7.0  89/11/23  22:23:32  mrose
 * Release 6.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include <ctype.h>
#include <stdio.h>
#include "SNMP-types.h"
#include "objects.h"
#include "tailor.h"

#include "internet.h"
#include "clns.h"

/*    DATA */

#define	MAXSYN	50

static object_syntax syntaxes[MAXSYN + 1];
static OS    synlast = syntaxes;

/*    INTEGER */

static int  integer_encode (x, pe)
integer	*x;
PE     *pe;
{
    if ((*pe = int2prim (*x)) == NULLPE)
	return NOTOK;

    return OK;
}


static int  integer_decode (x, pe)
integer **x;
PE	pe;
{
    integer	i = prim2num (pe);

    if (i == NOTOK && pe -> pe_errno != PE_ERR_NONE)
	return NOTOK;
    if ((*x = (integer *) malloc (sizeof **x)) == NULL)
	return NOTOK;
    **x = i;

    return OK;
}


static int  integer_free (x)
integer *x;
{
    free ((char *) x);
}


static int  integer_parse (x, s)
integer **x;
char   *s;
{
    long    l;

    if (sscanf (s, "%ld", &l) != 1)
	return NOTOK;
    if ((*x = (integer *) malloc (sizeof **x)) == NULL)
	return NOTOK;
    **x = (integer) l;

    return OK;
}


/* ARGSUSED */

static int  integer_print (x, os)
integer *x;
OS	os;
{
    printf ("%d", *x);
}


/* ARGSUSED */

static int  services_print (x, os)
integer *x;
OS	os;
{
    printf ("%s", sprintb ((int) *x,
			   "\020\01physical\02datalink/subnetwork\03internet\04transport\05session\06presentation\07application"));
}


/* ARGSUSED */

static int  privs_print (x, os)
integer *x;
OS	os;
{
    printf ("%s", sprintb ((int) *x,
			   "\020\01get\02get-next\03get-response\04set\05trap"));
}


static	add_integer ()
{
    (void) add_syntax ("INTEGER", integer_encode, integer_decode, integer_free,
		integer_parse, integer_print);
    (void) add_syntax ("Services", integer_encode, integer_decode,
		       integer_free, integer_parse, services_print);
    (void) add_syntax ("Privileges", integer_encode, integer_decode,
		       integer_free, integer_parse, privs_print);
}

/*    OCTET STRING */

static int  string_encode (x, pe)
struct qbuf *x;
PE     *pe;
{
    if ((*pe = qb2prim_aux (x, PE_CLASS_UNIV, PE_PRIM_OCTS, 0)) == NULLPE)
	return NOTOK;

    return OK;
}


static int  string_decode (x, pe)
struct qbuf **x;
PE	pe;
{
    struct qbuf *qb = prim2qb (pe);

    if (qb == NULL)
	return NOTOK;
    *x = qb;

    return OK;
}


static int  string_parse (x, s)
struct qbuf **x;
char   *s;
{
    struct qbuf *qb;

    if (strncmp (s, "0x", 2) == 0) {
	int	len;
	char   *p;

	s += 2;
	if ((len = strlen (s)) % 3 != 2)
	    return NOTOK;
	len /= 3, len++;
	if ((qb = str2qb (NULLCP, len, 1)) == NULL)
	    return NOTOK;
	p = qb -> qb_forw -> qb_data;
	while (*s) {
	    int	    i;

	    if (sscanf (s, "%x", &i) != 1) {
oops: ;
		qb_free (qb);
		return NOTOK;
	    }
	    *p++ = i & 0xff;

	    s += 2;
	    if (*s && *s++ != ':')
		goto oops;
	}
    }
    else
	if ((qb = str2qb (s, strlen (s), 1)) == NULL)
	    return NOTOK;

    *x = qb;

    return OK;    
}


/* ARGSUSED */

static int  string_print (x, os)
struct qbuf *x;
OS	os;
{
    register char *cp,
		  *ep;
    char   *p;
    register struct qbuf *qb;

    p = "0x";
    for (qb = x -> qb_forw; qb != x; qb = qb -> qb_forw)
	for (ep = (cp = qb -> qb_data) + qb -> qb_len; cp < ep; cp++) {
	    printf ("%s%02x", p, *cp & 0xff);
	    p = ":";
	}
}


/* ARGSUSED */

static int  string_display (x, os)
struct qbuf *x;
OS	os;
{
    register struct qbuf *qb;

    printf ("\"");
    for (qb = x -> qb_forw; qb != x; qb = qb -> qb_forw)
	printf ("%*.*s", qb -> qb_len, qb -> qb_len, qb -> qb_data);
    printf ("\"");
}


static	add_string ()
{
    (void) add_syntax ("OctetString", string_encode, string_decode, qb_free,
		string_parse, string_print);
    (void) add_syntax ("DisplayString", string_encode, string_decode, qb_free,
		string_parse, string_display);
    (void) add_syntax ("PhysAddress", string_encode, string_decode, qb_free,
		string_parse, string_print);
}

/*    OBJECT IDENTIFIER */

static int  object_encode (x, pe)
OID	x;
PE     *pe;
{
    if ((*pe = oid2prim (x)) == NULLPE)
	return NOTOK;

    return OK;
}


static int  object_decode (x, pe)
OID    *x;
PE	pe;
{
    OID    oid = prim2oid (pe);

    if (oid == NULLOID || (*x = oid_cpy (oid)) == NULLOID)
	return NOTOK;

    return OK;
}


static int  object_parse (x, s)
OID   *x;
char   *s;
{
    OID	    oid = text2oid (s);

    if (oid == NULL)
	return NOTOK;
    *x = oid;

    return OK;    
}


/* ARGSUSED */

static int  object_print (x, os)
OID	x;
OS	os;
{
    char  *cp,
	   ode[BUFSIZ];

    (void) strcpy (ode, oid2ode (x));
    printf ("%s", ode);
    if (strcmp (ode, cp = sprintoid (x)))
	printf (" (%s)", cp);
}


static	add_object ()
{
    (void) add_syntax ("ObjectID", object_encode, object_decode, oid_free,
		object_parse, object_print);
}

/*    NULL */

/* ARGSUSED */

static int  null_encode (x, pe)
char   *x;
PE     *pe;
{
    if ((*pe = pe_alloc (PE_CLASS_UNIV, PE_FORM_PRIM, PE_PRIM_NULL)) == NULLPE)
	return NOTOK;

    return OK;
}


/* ARGSUSED */

static int  null_decode (x, pe)
char  **x;
PE	pe;
{
    if ((*x = (char *) calloc (1, sizeof **x)) == NULL)
	return NOTOK;

    return OK;
}


static int  null_free (x)
char *x;
{
    free ((char *) x);
}


static int  null_parse (x, s)
char  **x;
char   *s;
{
    if (lexequ (s, "NULL"))
	return NOTOK;

    if ((*x = (char *) calloc (1, sizeof **x)) == NULL)
	return NOTOK;

    return OK;    
}


/* ARGSUSED */

static int  null_print (x, os)
char   *x;
OS	os;
{
    printf ("NULL");
}


static	add_null ()
{
    (void) add_syntax ("NULL", null_encode, null_decode, null_free, null_parse,
		null_print);
}

/*    IpAddress */

static int  ipaddr_encode (x, pe)
struct sockaddr_in *x;
PE     *pe;
{
    if ((*pe = str2prim ((char *) &x -> sin_addr, 4, PE_CLASS_APPL, 0))
	    == NULLPE)
	return NOTOK;

    return OK;
}


static int  ipaddr_decode (x, pe)
struct sockaddr_in **x;
PE	pe;
{
    struct type_SNMP_IpAddress *ip;
    struct qbuf *qb;
    struct sockaddr_in *isock;

    if (decode_SNMP_IpAddress (pe, 1, NULLIP, NULLVP, &ip) == NOTOK)
	return NOTOK;
    if (qb_pullup (ip) == NOTOK
	    || (isock = (struct sockaddr_in *) calloc (1, sizeof *isock))
		    == NULL) {
	free_SNMP_IpAddress (ip);
	return NOTOK;
    }
    if ((qb = ip -> qb_forw) -> qb_len != 4) {
	free ((char *) isock);
	free_SNMP_IpAddress (ip);
	return NOTOK;
    }
    isock -> sin_family = AF_INET;
    bcopy (qb -> qb_data,
	   (char *) &isock -> sin_addr,
	   sizeof isock -> sin_addr);

    *x = isock;

    free_SNMP_IpAddress (ip);
    return OK;
}


static int  ipaddr_free (x)
struct sockaddr_in *x;
{
    free ((char *) x);
}


static int  ipaddr_parse (x, s)
struct sockaddr_in **x;
char   *s;
{
    register struct hostent *hp = gethostbystring (s);
    register struct sockaddr_in *isock;

    if (hp == NULL)
	return NOTOK;

    if ((isock = (struct sockaddr_in *) calloc (1, sizeof *isock)) == NULL)
	return NOTOK;
    isock -> sin_family = AF_INET;
    inaddr_copy (hp, isock);
    *x = isock;

    return OK;    
}


/* ARGSUSED */

static int  ipaddr_print (x, os)
struct sockaddr_in *x;
OS	os;
{
    printf ("%s", inet_ntoa (x -> sin_addr));
}


static	add_ipaddr ()
{
    (void) add_syntax ("IpAddress", ipaddr_encode, ipaddr_decode, ipaddr_free,
		ipaddr_parse, ipaddr_print);
}

/*    NetworkAddress */

/* good enough for now (and probably forever)... */

static	add_netaddr ()
{
    (void) add_syntax ("NetworkAddress", ipaddr_encode, ipaddr_decode,
		       ipaddr_free, ipaddr_parse, ipaddr_print);
}

/*    UNSIGNED LONGs */

u_long	prim2ulong (pe)		/* also used in SNMP-capable gawk... */
register PE	pe;
{
    register u_long   i;
    register PElementData dp,
			  ep;

    if (pe -> pe_form != PE_FORM_PRIM || (dp = pe -> pe_prim) == NULLPED)
	return pe_seterr (pe, PE_ERR_PRIM, 0);
    if (pe -> pe_len > sizeof (i) + 1)
	return pe_seterr (pe, PE_ERR_OVER, 0);
    if (pe -> pe_len == sizeof (i) + 1 && (*dp & 0x7f))
	return pe_seterr (pe, PE_ERR_OVER, 0);
    if (*dp & 0x80)
	return pe_seterr (pe, PE_ERR_SIGNED, 0);

    pe -> pe_errno = PE_ERR_NONE;	/* in case result is ZERO-valued */
    i = 0L;
    for (ep = dp + pe -> pe_len; dp < ep;)
	i = (i << 8) | (*dp++ & 0xff);

    return i;
}


static PE  ulong2prim (i, class, id)
register u_long i;
PElementClass	class;
PElementID	id;
{
    int	    extend;
    register int    n;
    register u_long mask;
    register PElementData dp;
    register PE	    pe;

    if ((pe = pe_alloc (class, PE_FORM_PRIM, id)) == NULLPE)
	return NULLPE;

    mask = 0xff << (((n = sizeof i) - 1) * 8);
    while (n > 1 && (i & mask) == 0)
	mask >>= 8, n--;
    extend = (i & (0x80 << ((n - 1) * 8))) ? 1 : 0;

    if ((pe -> pe_prim = PEDalloc (n + extend)) == NULLPED) {
	pe_free (pe);
	return NULLPE;
    }

    for (dp = pe -> pe_prim + (pe -> pe_len = n + extend); n-- > 0; i >>= 8)
	*--dp = i & 0xff;
    if (extend)
	*--dp = 0x00;

    return pe;
}

/*    Counter */

static int  counter_encode (x, pe)
u_long	*x;
PE     *pe;
{
    if ((*pe = ulong2prim (*x, PE_CLASS_APPL, 1)) == NULLPE)
	return NOTOK;

    return OK;
}


static int  counter_decode (x, pe)
u_long **x;
PE	pe;
{
    u_long	i = prim2ulong (pe);

    if (i == 0 && pe -> pe_errno != PE_ERR_NONE)
	return NOTOK;
    if ((*x = (u_long *) malloc (sizeof **x)) == NULL)
	return NOTOK;
    **x = i;

    return OK;
}


static int  counter_free (x)
u_long *x;
{
    free ((char *) x);
}


static int  counter_parse (x, s)
u_long **x;
char   *s;
{
    u_long  i;

    if (sscanf (s, "%U", &i) != 1)
	return NOTOK;
    if ((*x = (u_long *) malloc (sizeof **x)) == NULL)
	return NOTOK;
    **x = i;

    return OK;    
}


/* ARGSUSED */

static int  counter_print (x, os)
u_long *x;
OS	os;
{
    printf ("%U", *x);
}


static	add_counter ()
{
    (void) add_syntax ("Counter", counter_encode, counter_decode, counter_free,
		counter_parse, counter_print);
}

/*    Gauge */

static int  gauge_encode (x, pe)
u_long	*x;
PE     *pe;
{
    if ((*pe = ulong2prim (*x, PE_CLASS_APPL, 2)) == NULLPE)
	return NOTOK;

    return OK;
}


static	add_gauge ()
{
    (void) add_syntax ("Gauge", gauge_encode, counter_decode, counter_free,
		counter_parse, counter_print);
}

/*    TimeTicks */

static int  timeticks_encode (x, pe)
u_long	*x;
PE     *pe;
{
    if ((*pe = ulong2prim (*x, PE_CLASS_APPL, 3)) == NULLPE)
	return NOTOK;

    return OK;
}


/* ARGSUSED */

static int  timeticks_print (x, os)
u_long *x;
OS	os;
{
    u_long  d,
	    h,
	    m,
	    s,
	    ds;

    ds = *x;
    s = ds / 100, ds = ds % 100;
    m = s / 60, s = s % 60;
    h = m / 60, m = m % 60;
    d = h / 24, h = h % 24;

    if (d > 0)
	printf ("%d days, ", d);
    if (d > 0 || h > 0)
	printf ("%d hours, ", h);
    if (d > 0 || h > 0 || m > 0)
	printf ("%d minutes, ", m);
    printf ("%d", s);
    if (ds > 0)
	printf (".%02d", ds);
    printf (" seconds (%U timeticks)", *x);
}


static	add_timeticks ()
{
    (void) add_syntax ("TimeTicks", timeticks_encode, counter_decode,
		       counter_free, counter_parse, timeticks_print);
}

/*    CnlpAddress */

static int  clnpaddr_encode (x, pe)
struct sockaddr_iso *x;
PE     *pe;
{
    char    buffer[sizeof x -> siso_data + 1];

    buffer[0] = x -> siso_nlen & 0xff;
    bcopy (x -> siso_data, buffer + 1, (int) x -> siso_nlen);

    if ((*pe = str2prim (buffer, (int) (x -> siso_nlen + 1), PE_CLASS_APPL,
			 5)) == NULLPE)
	return NOTOK;

    return OK;
}


static int  clnpaddr_decode (x, pe)
struct sockaddr_iso **x;
PE	pe;
{
    int	    len;
    struct type_SNMP_ClnpAddress *clnp;
    struct qbuf *qb;
    struct sockaddr_iso *isock;

    if (decode_SNMP_ClnpAddress (pe, 1, NULLIP, NULLVP, &clnp) == NOTOK)
	return NOTOK;
    if (qb_pullup (clnp) == NOTOK
	    || (isock = (struct sockaddr_iso *) calloc (1, sizeof *isock))
		    == NULL) {
	free_SNMP_ClnpAddress (clnp);
	return NOTOK;
    }
    qb = clnp -> qb_forw;
    isock -> siso_family = AF_ISO;
    if ((len = qb -> qb_data[0] & 0xff) >= qb -> qb_len)
	len = qb -> qb_len - 1;
    bcopy (qb -> qb_data + 1, isock -> siso_data,
	   (int) (isock -> siso_nlen = len));

    *x = isock;

    free_SNMP_ClnpAddress (clnp);
    return OK;
}


static int  clnpaddr_free (x)
struct sockaddr_iso *x;
{
    free ((char *) x);
}


static int  clnpaddr_parse (x, s)
struct sockaddr_iso **x;
char   *s;
{
    register struct sockaddr_iso *isock;

    if ((isock = (struct sockaddr_iso *) calloc (1, sizeof *isock)) == NULL)
	return NOTOK;
    isock -> siso_family = AF_ISO;
    isock -> siso_nlen = implode ((u_char *) isock -> siso_data, s,
				  strlen (s));
    *x = isock;

    return OK;    
}


/* ARGSUSED */

static int  clnpaddr_print (x, os)
struct sockaddr_iso *x;
OS	os;
{
    char    buffer[sizeof x -> siso_data * 2 + 1];

    buffer[explode (buffer, (u_char *) x -> siso_data, (int) x -> siso_nlen)] =
	NULL;
    printf ("NS+%s", buffer);
}


static	add_clnpaddr ()
{
    (void) add_syntax ("ClnpAddress", clnpaddr_encode, clnpaddr_decode,
		       clnpaddr_free, clnpaddr_parse, clnpaddr_print);
}

/*  */

int	readsyntax ()
{
    add_integer ();
    add_string ();
    add_object ();
    add_null ();
    add_ipaddr ();
    add_netaddr ();
    add_counter ();
    add_gauge ();
    add_timeticks ();

    add_clnpaddr ();
}

/*  */

int	add_syntax (name, f_encode, f_decode, f_free, f_parse, f_print)
char   *name;
IFP	f_encode,
    	f_decode,
    	f_free,
    	f_parse,
	f_print;
{
    int	    i;
    register OS	    os = synlast++;

    if ((i = synlast - syntaxes) >= MAXSYN)
	return NOTOK;

    bzero ((char *) os, sizeof *os);
    os -> os_name = name;
    os -> os_encode = f_encode;
    os -> os_decode = f_decode;
    os -> os_free = f_free;
    os -> os_parse = f_parse;
    os -> os_print = f_print;

    return i;
}

/*  */

OS	text2syn (name)
char   *name;
{
    register OS	    os;

    for (os = syntaxes; os < synlast; os++)
	if (strcmp (os -> os_name, name) == 0)
	    return os;

    return NULLOS;
}