/*------------------------------------------------------------------------ * snb2a - convert the list of bindings from internal form into ASN.1 *------------------------------------------------------------------------ */ int snb2a(struct req_desc *rqdp) { register u_char *bp; int len; struct snbentry *bl; u_char *ap; for (bl = rqdp->bindlf; bl; bl = bl->sb_next) { bp = snmpbuff; /* used for temporary working space */ *bp++ = ASN1_OBJID; bp += a1writeoid(bp, &bl->sb_oid); bp += a1writeval(bl, bp); /* * We need to allocate bytes in sb_a1str but can't do it * until we know how many bytes it takes to write the * length of the binding, so we write that length into * snmpbuff at the end of the binding. Then we can alloc * space, and transfer the data. */ len = a1writelen(bp, bp - snmpbuff); bl->sb_a1slen = bp - snmpbuff + len + 1; ap = bl->sb_a1str = (u_char *) getmem(bl->sb_a1slen); bl->sb_a1dynstr = TRUE; /* dynamically allocated */ *ap++ = ASN1_SEQ; memcpy(ap, bp, len); /* write in the length spec. */ ap += len; memcpy(ap, snmpbuff, bp - snmpbuff); } return OK; }
/*------------------------------------------------------------------------ * a1writeval - convert the value of a variable into ASN.1 equivalent. *------------------------------------------------------------------------ */ int a1writeval(struct snbentry *bl, u_char *bp) { u_char *origbp; origbp = bp; *bp++ = SVTYPE(bl); switch(SVTYPE(bl)) { case ASN1_INT: case ASN1_COUNTER: case ASN1_GAUGE: case ASN1_TIMETICKS: bp += a1writeint(SVINT(bl), bp, SVTYPE(bl)); break; case ASN1_NULL: *bp++ = (u_char) 0; break; case ASN1_OCTSTR: bp += a1writelen(bp, SVSTRLEN(bl)); memcpy(bp, SVSTR(bl), SVSTRLEN(bl)); bp += SVSTRLEN(bl); freemem(SVSTR(bl), SVSTRLEN(bl)); break; case ASN1_IPADDR: *bp++ = IP_ALEN; memcpy(bp, &SVIPADDR(bl), IP_ALEN); bp += IP_ALEN; break; case ASN1_OBJID: bp += a1writeoid(bp, &bl->sb_val.sv_val.sv_oid); break; default: break; } return bp - origbp; }
/*------------------------------------------------------------------------ * mksnmp - make an snmp packet and return its length *------------------------------------------------------------------------ */ int mksnmp(struct req_desc *rqdp, u_char *snmppack, u_char pdutype) { register u_char *pp, *cp; struct snbentry *bl; u_char tmpbuff[40]; int len, mtu, estlen; pp = snmpbuff; if (rqdp->reqidlen == 0) { /* if id len == 0, get new reqid */ memcpy(rqdp->reqid, (char *) &clktime, sizeof(clktime)); rqdp->reqidlen = sizeof(clktime); } snb2a(rqdp); /* convert bindings to ASN.1 notation */ /* check total length of the packet to be created */ mtu = IP_MAXLEN; /* add up total length of ASN.1 representations of variables */ for (estlen=0, bl=rqdp->bindlf; estlen<mtu && bl; bl=bl->sb_next) estlen += bl->sb_a1slen; /* * if too long, or if adding the header makes it too long, * set error status to tooBig and return */ if (bl || (estlen + SNMAXHLEN >= mtu)) { rqdp->err_stat = SERR_TOO_BIG; rqdp->err_idx = 0; return SYSERR; } /* go backwards through snbentry, writing out the bindings */ for (bl=rqdp->bindle; bl; bl=bl->sb_prev) { cp = &bl->sb_a1str[bl->sb_a1slen-1]; while (cp >= bl->sb_a1str) *pp++ = *cp--; } /* write the length of the bindings and an ASN1_SEQ type */ len = a1writelen(tmpbuff, pp - snmpbuff); for (cp = &tmpbuff[len-1]; cp >= tmpbuff; ) *pp++ = *cp--; *pp++ = ASN1_SEQ; /* write the error index and error status -- 1 byte integers */ *pp++ = (u_char) rqdp->err_idx; *pp++ = (u_char) 1; *pp++ = ASN1_INT; *pp++ = (u_char) rqdp->err_stat; *pp++ = (u_char) 1; *pp++ = ASN1_INT; /* write the request id, its length, and its type */ for (cp = &rqdp->reqid[rqdp->reqidlen-1]; cp >= rqdp->reqid; ) *pp++ = *cp--; *pp++ = rqdp->reqidlen; *pp++ = ASN1_INT; /* write the packet length and pdutype */ len = a1writelen(tmpbuff, pp - snmpbuff); for (cp = &tmpbuff[len-1]; cp >= tmpbuff; ) *pp++ = *cp--; *pp++ = pdutype; /* write the community and the version */ memcpy(pp, SNVCBACK, SNVCLEN); pp += SNVCLEN; /* write the total packet length */ len = a1writelen(tmpbuff, pp - snmpbuff); for (cp = &tmpbuff[len-1]; cp >= tmpbuff; ) *pp++ = *cp--; *pp++ = ASN1_SEQ; /* reverse the entire finished packet */ for (--pp, cp = snmppack; pp >= snmpbuff; ) *cp++ = *pp--; return cp - snmppack; }