static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
					struct snmp_object **obj)
{
	unsigned int cls, con, tag, len, idlen;
	unsigned short type;
	unsigned char *eoc, *end, *p;
	unsigned long *lp, *id;
	unsigned long ul;
	long l;

	*obj = NULL;
	id = NULL;

	if (!asn1_header_decode(ctx, &eoc, &cls, &con, &tag))
		return 0;

	if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
		return 0;

	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
		return 0;

	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI)
		return 0;

	if (!asn1_oid_decode(ctx, end, &id, &idlen))
		return 0;

	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) {
		kfree(id);
		return 0;
	}

	if (con != ASN1_PRI) {
		kfree(id);
		return 0;
	}

	type = 0;
	if (!snmp_tag_cls2syntax(tag, cls, &type)) {
		kfree(id);
		return 0;
	}

	l = 0;
	switch (type) {
		case SNMP_INTEGER:
			len = sizeof(long);
			if (!asn1_long_decode(ctx, end, &l)) {
				kfree(id);
				return 0;
			}
			*obj = kmalloc(sizeof(struct snmp_object) + len,
				       GFP_ATOMIC);
			if (*obj == NULL) {
				kfree(id);
				if (net_ratelimit())
					printk("OOM in bsalg (%d)\n", __LINE__);
				return 0;
			}
			(*obj)->syntax.l[0] = l;
			break;
		case SNMP_OCTETSTR:
		case SNMP_OPAQUE:
			if (!asn1_octets_decode(ctx, end, &p, &len)) {
				kfree(id);
				return 0;
			}
			*obj = kmalloc(sizeof(struct snmp_object) + len,
				       GFP_ATOMIC);
			if (*obj == NULL) {
				kfree(id);
				if (net_ratelimit())
					printk("OOM in bsalg (%d)\n", __LINE__);
				return 0;
			}
			memcpy((*obj)->syntax.c, p, len);
			kfree(p);
			break;
		case SNMP_NULL:
		case SNMP_NOSUCHOBJECT:
		case SNMP_NOSUCHINSTANCE:
		case SNMP_ENDOFMIBVIEW:
			len = 0;
			*obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC);
			if (*obj == NULL) {
				kfree(id);
				if (net_ratelimit())
					printk("OOM in bsalg (%d)\n", __LINE__);
				return 0;
			}
			if (!asn1_null_decode(ctx, end)) {
				kfree(id);
				kfree(*obj);
				*obj = NULL;
				return 0;
			}
			break;
		case SNMP_OBJECTID:
			if (!asn1_oid_decode(ctx, end, (unsigned long **)&lp, &len)) {
				kfree(id);
				return 0;
			}
			len *= sizeof(unsigned long);
			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);
			if (*obj == NULL) {
				kfree(lp);
				kfree(id);
				if (net_ratelimit())
					printk("OOM in bsalg (%d)\n", __LINE__);
				return 0;
			}
			memcpy((*obj)->syntax.ul, lp, len);
			kfree(lp);
			break;
		case SNMP_IPADDR:
			if (!asn1_octets_decode(ctx, end, &p, &len)) {
				kfree(id);
				return 0;
			}
			if (len != 4) {
				kfree(p);
				kfree(id);
				return 0;
			}
			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);
			if (*obj == NULL) {
				kfree(p);
				kfree(id);
				if (net_ratelimit())
					printk("OOM in bsalg (%d)\n", __LINE__);
				return 0;
			}
			memcpy((*obj)->syntax.uc, p, len);
			kfree(p);
			break;
		case SNMP_COUNTER:
		case SNMP_GAUGE:
		case SNMP_TIMETICKS:
			len = sizeof(unsigned long);
			if (!asn1_ulong_decode(ctx, end, &ul)) {
				kfree(id);
				return 0;
			}
			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);
			if (*obj == NULL) {
				kfree(id);
				if (net_ratelimit())
					printk("OOM in bsalg (%d)\n", __LINE__);
				return 0;
			}
			(*obj)->syntax.ul[0] = ul;
			break;
		default:
			kfree(id);
			return 0;
	}

	(*obj)->syntax_len = len;
	(*obj)->type = type;
	(*obj)->id = id;
	(*obj)->id_len = idlen;

	if (!asn1_eoc_decode(ctx, eoc)) {
		kfree(id);
		kfree(*obj);
		*obj = NULL;
		return 0;
	}
	return 1;
}