Plan 9 from Bell Labs’s /usr/web/sources/contrib/rsc/snmp/a1.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <ip.h>
#include "a1.h"

int
a1readlen(uchar *a, int *llen)
{
	int len, i;
	if((a[0] & 0x80) == 0) {
		*llen = 1;
		return a[0];
	}
	*llen = (*a++ & 0x7f) + 1;
	for(i=0, len=0; i<*llen-1; i++)
		len = (len << 8) | *a++;
	return len;
}

int
a1readint(uchar *a, int len)
{
	int tot, neg, tlen;

	tlen = len;
	if(len > sizeof(int)) return 0;
	tot = *a & 0x7f;
	neg = *a & 0x80;

	for(tlen--, a++; tlen > 0; tlen--, a++)
		tot = (tot << 8) | *a;
	if(neg)
		tot -= (1<<((len*8)-1));
	return tot;
}

char *snmpatype[] = { "get", "getn", "resp", "set", "trap" };

void
Sfree(Snmp *s) 
{
	free(s->pdu);
	free(s);
}
	
Snmp*
Salloc(void)
{
	Snmp *s;
	if((s = malloc(sizeof(*s))) == 0)
		return 0;
	memset(s, 0, sizeof(*s));
	return s;
}

int
objidfmt(char *s, int ns, uchar *a, int na)
{
	int i, n, dot;

	dot = 0;
	n = snprint(s, ns, "%d.%d",
		a[0]/40, a[0]%40);
	for(i=1; i<na; i++) {
		dot = dot << 7 | (int)(a[i] & ~0x80);
		if((a[i] & 0x80) == 0) {
			n += snprint(s+n, ns-n,
				".%d", dot);
			dot = 0;
		}
	}
	return n;
}

void
Sprint(Snmp *s)
{
	int i;
	char buf[Objidlen];

	print("snmp v%d %s %s req %d estat %d eindex %d\n",
		s->vers, s->private ? "private" : "public",
		0xa0 <= s->type && s->type <= 0xa4 ? snmpatype[s->type-0xa0] : "<bad type>",
		s->reqid, s->estat, s->eindex);

	for(i=0; i<s->npdu; i++){
		print("\t%s ", s->pdu[i].objid);
		switch(s->pdu[i].type) {
		case Anull:
			break;
		case Aint:
			print("int %d", s->pdu[i].i);
			break;
		case Acounter:
			print("counter %d", s->pdu[i].i);
			break;
		case Agauge:
			print("gauge %d", s->pdu[i].i);
			break;
		case Atimeticks:
			print("timeticks %d", s->pdu[i].i);
			break;
		case Aoctstr:
			print("octstr %.*s", utfnlen(s->pdu[i].s, s->pdu[i].len), s->pdu[i].s);
			break;
		case Aobjid:
			objidfmt(buf, sizeof buf, (uchar*)s->pdu[i].s, s->pdu[i].len);
			print("objid %s", buf);
			break;
		case Aipaddr:
			print("ipaddr %V", (uchar*)s->pdu[i].s);
			break;
		default:
			print("unknown type %d", s->pdu[i].type);
			break;
		}
		print("\n");
	}
}

int
Sparse(void *va, int na, Snmp *dst)
{
	SnmpPdu *pdu;
	uchar *a = va;
	uchar *ea = a+na;
	int j, tlen, llen, npdu;

	chat("Sparse %d...", ea-a);

	if(dst == 0){
		werrstr("bad args to Sparse");
		return -1;
	}

	chat(".");
	if(*a++ != Aseq || (tlen = a1readlen(a, &llen)) < 0)
		goto die;

	chat("tlen=%d...", tlen);
	a += llen;
	if(a+tlen < ea) 
		ea = a+tlen;

	if(a > ea) goto die;

	if(*a++ != Aint) goto die;
	if((j=a1readlen(a, &llen)) < 0) goto die;
	chat("llen =%d\n", llen);
	a++;
	dst->vers = a1readint(a, j);
	a += j;

	chat("vers=%d...", dst->vers);

	if(a > ea) goto die;

	chat("nxt=%d", *a);
	if(*a++ != Aoctstr || (j=a1readlen(a, &llen)) < 0) goto die;
	a += llen;

	if(a > ea) goto diespace;

	if(strncmp((char*)a, "private", j) == 0)
		dst->private = 1;
	else
		dst->private = 0;

	chat("(%d)%s...", j, dst->private?"private":"public");

	a += j;
	chat("%x", *a);
	if(*a < 0xa0 || *a > 0xa4){
		werrstr("bad pkt type");
		goto die;
	}

	dst->type = *a;
	a++;
	chat("type=%s", snmpatype[dst->type-0xa0]);
	if((j = a1readlen(a, &llen)) < 0) goto die;
	a += llen;

	if(ea < a+j) goto die;

	if(*a++ != Aint || (j=a1readlen(a, &llen)) < 0) goto die;
	a += llen;

	dst->reqid = a1readint(a, j);
	a += j;

	if(a > ea) goto die;

	if(*a++ != Aint || *a++ != 1) goto die;
	dst->estat = *a++;

	if(*a++ != Aint || *a++ != 1) goto die;
	dst->eindex = *a++;

	if(a > ea) goto die;

	if(*a++ != Aseq || (j = a1readlen(a, &llen)) < 0) goto die;
	a += llen;

	if(ea < a+j) goto die;

	npdu = 0;
	while(a < ea && npdu < Mpdu) {
		chat("pdu...");
		++npdu;
		chat("npdu=%d", npdu);
		pdu = &dst->pdu[npdu-1];
		if(*a++ != Aseq || (a1readlen(a, &llen)) < 0) goto die;
		a += llen;
		if(a > ea) goto die;

		if(*a++ != Aobjid || (j=a1readlen(a, &llen)) < 0) goto die;
		a += llen;
		if(a > ea) goto die;

		objidfmt(pdu->objid, Objidlen, a, j);
		chat("objid %s...", pdu->objid);

		a += j;
		pdu->type = *a;
		chat("type %d...", pdu->type);
		a++;
		if(a > ea) goto die;
		if((j = a1readlen(a, &llen)) < 0) goto die;
		a += llen;
		if(a > ea) goto die;
		pdu->len = j;
		chat("len %d...", j);
		switch(pdu->type) {
		case Aint:
		case Acounter:
		case Agauge:
		case Atimeticks:
			pdu->i = a1readint(a, j);
			break;
		case Aoctstr:
		case Aobjid:
		case Aipaddr:
		default:
			pdu->s = (char*)a;
			break;
		}
		a += j;
		if(a > ea) goto die;
	}
	dst->npdu = npdu;
	return 0;

diespace:
	werrstr("out of space");
die:
	chat("die...a=%d ea=%d", a-(uchar*)va, ea-(uchar*)va);
	return -1;
}

static int
wobjid(uchar *oa, char *s)
{
	uchar *a = oa;
	int i, j, dot;
	int dots[32];
	char *f[32];
	int nf;

	s = strdup(s);
	nf = getfields(s, f, 32, 0, ".");
	if(nf < 0) {
		free(s);
		return 0;
	}
	for(i=0; i<nf; i++)
		dots[i] = atoi(f[i]);
	for(j=nf-1; j>=2; j--) {
		dot = dots[j];
		*--a = dot & 0x7f;
		dot >>= 7;
		while(dot) {
			*--a = 0x80|(dot&0x7f);
			dot >>= 7;
		}
	}
	*--a = dots[0] * 40 + dots[1];
	free(s);
	return (oa-a);
}

static int
wlen(uchar *oa, int len)
{
	uchar *a = oa;
	if(len < 128) {
		*--a = len;
		return 1;
	}
	while(len) {
		*--a = len;
		len >>= 8;
	}
	--a;
	*a = (oa-a-1)|0x80;
	return (oa-a);
}

static int
wint(uchar *oa, int i)
{
	int neg, n;
	uchar *a = oa;
	n = i;
	neg = 0;
	if(n < 0) {
		neg = 1;
		n = -n;
	}
	*--a = n;
	n >>= 8;
	while(n) {
		*--a = n;
		n >>= 8;
	}
	if(*a & 0x80) 
		*--a = 0;
	if(neg) *a |= 0x80;
	return (oa-a);
}

int
Sunparse(Snmp *s, void *va, int na)
{
	uchar *atop = va;
	uchar *a = va;
	uchar *oa;
	uchar *ea = a+na;
	SnmpPdu *pdu;
	int i,l;

	/* we build the packet backwards at the end of
	 * the buffer and then memmove it to the 
	 * beginning
	 */

	a = ea;
	pdu = &s->pdu[s->npdu];
	for(i=s->npdu-1; i>=0; i--) {
		oa = a;
		pdu--;
		switch(pdu->type) {
		case Aint:
		case Acounter:
		case Agauge:
		case Atimeticks:
			a -= wint(a, pdu->i);
			break;
		case Aobjid:
			a -= wobjid(a, pdu->s);
			break;

		case Anull:
		default:
			/* do nothing */
			break;
		case Aipaddr:
			pdu->len = 4;
			/* fall through */
		case Aoctstr:
			a -= pdu->len;
			memcpy(a, pdu->s, pdu->len);
			break;
		}

		pdu->len = oa-a;
		/* now write len of pdu data*/
		a -= wlen(a, pdu->len);
		*--a = pdu->type;

		/* now write objid */
		a -= (l=wobjid(a, pdu->objid));
		a -= wlen(a, l);
		*--a = Aobjid;
		
		/* now write len of pdu */
		a -= wlen(a, oa-a);
		*--a = Aseq;
	}

	/* now write length of all pdus */
	a -= wlen(a, ea-a);
	*--a = Aseq;

	/* eindex */
	*--a = 0;
	*--a = 1;
	*--a = Aint;

	/* estat */
	*--a = 0;
	*--a = 1;
	*--a = Aint;

	/* request id */
	a -= (l=wint(a, s->reqid));
	a -= wlen(a, l);
	*--a = Aint;

	/* let's just toss the length of the packet so far
	 * in here, just to make sure we haven't forgotten.
	 * bit decay, you know.
	 */
	a -= wlen(a, (ea-a));
	/* DO NOT *--a = Aseq; [sic] */

	*--a = s->type;
	
	if(s->private) {
		a -= 7;
		memcpy(a, "private", 7);
		a -= wlen(a, 7);
	} else {
		a -= 6;
		memcpy(a, "public", 6);
		a -= wlen(a, 6);
	}

	*--a = Aoctstr;

	a -= (l=wint(a, s->vers));
	a -= wlen(a, l);
	*--a = Aint;

	/* bit decay check */
	a -= wlen(a, ea-a);
	*--a = Aseq;

	/* done! */
	memmove(atop, a, ea-a);
	return ea-a;
}

int readflag, alarmflag;

int
alarmtr(void*, char *why)
{
	if(!readflag)
		return 0;

	if(strcmp(why, "alarm")==0) {
		alarmflag++;
		return 1;
	}
	return 0;
}

int
dosnmp(int nfd, Snmp *s, Snmp *srep)
{
	int nn, n, reqid;
	static char buf[4096];
	static int reg;

	if(!reg) {
		atnotify(alarmtr, 1);
		reg = 1;
	}

	if(s == 0 || srep == 0){
		werrstr("bad args to dosnmp");
		return -1;
	}

	if(s->reqid == 0)
		s->reqid = (nsec()&0x7FFE)+1;
	reqid = s->reqid;
	n = Sunparse(s, buf, sizeof(buf));

	if(n <= 0){
		werrstr("Sunparse: %r");
		return -1;
	}

	nn = write(nfd, buf, n);
	if(nn != n) {
		werrstr("write failed: %r");
		return -1;
	}

	memset(srep, 0, sizeof(*srep));
	alarmflag = 0;
	readflag = 1;
	alarm(5000);
	do {
		n = read(nfd, buf, sizeof buf);
		if(n > 0){ 
			chat("sparse %d?", n);
			memset(srep, 0, sizeof(*srep));
			if(Sparse(buf, n, srep) < 0){
				print("parse error: %r\n");
				continue;
			}
			if(srep->reqid != reqid)
				print("mismatch id %d %d\n", srep->reqid, reqid);
		}
	} while(!alarmflag && n > 0 && srep->reqid != reqid);

	alarm(0);
	if(alarmflag){
		werrstr("alarmed");
		return -1;
	}
	readflag = 0;
	if(srep->reqid == reqid) {
		return 0;
	}
	if(n < 0)
		werrstr("read failed: %r");
	else if(n == 0)
		werrstr("read got eof");
	else
		werrstr("got reqid %d wanted %d", srep->reqid, reqid);
	return -1;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].