diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 60afa77f7c430a45a9886e8412983f7164791eb6..7fe3e84dbb72cd53c916365f74ff128bf3356079 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
@@ -797,6 +797,63 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
 	return 0;
 }
 
+int
+asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) {
+	uint8_t *b, *end;
+	unsigned long l;
+	size_t size;
+
+	if(!iptr || !iptr->buf || !lptr) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	b = iptr->buf;
+	size = iptr->size;
+	end = b + size;
+
+	/* If all extra leading bytes are zeroes, ignore them */
+	for(; size > sizeof(unsigned long); b++, size--) {
+		if(*b) {
+			/* Value won't fit unsigned long */
+			errno = ERANGE;
+			return -1;
+		}
+	}
+
+	/* Conversion engine */
+	for(l = 0; b < end; b++)
+		l = (l << 8) | *b;
+
+	*lptr = l;
+	return 0;
+}
+
+int
+asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) {
+	uint8_t *buf;
+	uint8_t *end;
+	uint8_t *b;
+	int shr;
+
+	if(value <= LONG_MAX)
+		return asn_long2INTEGER(st, value);
+
+	buf = (uint8_t *)MALLOC(1 + sizeof(value));
+	if(!buf) return -1;
+
+	end = buf + (sizeof(value) + 1);
+	buf[0] = 0;
+	for(b = buf, shr = (sizeof(long)-1)*8; b < end; shr -= 8)
+		*(++b) = value >> shr;
+
+	if(st->buf) FREEMEM(st->buf);
+	st->buf = buf;
+	st->size = 1 + sizeof(value);
+
+	return 0;
+}
+
 int
 asn_long2INTEGER(INTEGER_t *st, long value) {
 	uint8_t *buf, *bp;
diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h
index 62832b12e1271e1f27a5edd5b4a0f82986ff2fc3..b87c794c0ba7fa18bd80001b6f76aee5ef01a550 100644
--- a/skeletons/INTEGER.h
+++ b/skeletons/INTEGER.h
@@ -51,7 +51,9 @@ per_type_encoder_f INTEGER_encode_uper;
  * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()).
  */
 int asn_INTEGER2long(const INTEGER_t *i, long *l);
+int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l);
 int asn_long2INTEGER(INTEGER_t *i, long l);
+int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l);
 
 /*
  * Convert the integer value into the corresponding enumeration map entry.
diff --git a/skeletons/asn_system.h b/skeletons/asn_system.h
index fe696454e1d12c1d0f62d7d2b189131f6203c082..193a97506382ef16dd59a062fa8478292cfffc27 100644
--- a/skeletons/asn_system.h
+++ b/skeletons/asn_system.h
@@ -17,6 +17,7 @@
 #include <stdlib.h>	/* For *alloc(3) */
 #include <string.h>	/* For memcpy(3) */
 #include <sys/types.h>	/* For size_t */
+#include <limits.h>	/* For LONG_MAX */
 #include <stdarg.h>	/* For va_start */
 #include <stddef.h>	/* for offsetof and ptrdiff_t */
 
diff --git a/skeletons/tests/check-INTEGER.c b/skeletons/tests/check-INTEGER.c
index bacb618e75cf41b6efb787a256089adaf793ea4a..a299fcd58c5a6359ad72d26e19153589823498cc 100644
--- a/skeletons/tests/check-INTEGER.c
+++ b/skeletons/tests/check-INTEGER.c
@@ -74,6 +74,74 @@ check(uint8_t *buf, int size, long check_long, int check_ret) {
 	}
 }
 
+static void
+check_unsigned(uint8_t *buf, int size, unsigned long check_long, int check_ret) {
+	char scratch[128];
+	char verify[32];
+	INTEGER_t val;
+	uint8_t *buf_end = buf + size;
+	int ret;
+	unsigned long rlong = 123;
+
+	assert(buf);
+	assert(size >= 0);
+
+	val.buf = buf;
+	val.size = size;
+
+	printf("Testing: [");
+	for(; buf < buf_end; buf++) {
+		if(buf != val.buf) printf(":");
+		printf("%02x", *buf);
+	}
+	printf("]: ");
+
+	ret = asn_INTEGER2ulong(&val, &rlong);
+	printf(" (%lu, %d) vs (%lu, %d)\n",
+		rlong, ret, check_long, check_ret);
+	assert(ret == check_ret);
+	printf("%lu %lu\n", rlong, check_long);
+	assert(rlong == check_long);
+
+	if(check_ret == 0) {
+		INTEGER_t val2;
+		unsigned long rlong2;
+		val2.buf = 0;
+		val2.size = 0;
+		ret = asn_ulong2INTEGER(&val2, rlong);
+		assert(ret == 0);
+		assert(val2.buf);
+		if(val2.size > val.size) {
+			/* At least as compact */
+			printf("val2.size=%d, val.size=%d\n",
+				(int)val2.size, (int)val.size);
+			assert(val2.size <= val.size);
+		}
+		ret = asn_INTEGER2ulong(&val, &rlong2);
+		assert(ret == 0);
+		assert(rlong == rlong2);
+	}
+
+	return 0;
+
+	shared_scratch_start = scratch;
+	ret = INTEGER_print(&asn_DEF_INTEGER, &val, 0, _print2buf, scratch);
+	assert(shared_scratch_start < scratch + sizeof(scratch));
+	assert(ret == 0);
+	ret = snprintf(verify, sizeof(verify), "%ld", check_long);
+	assert(ret < sizeof(verify));
+	ret = strcmp(scratch, verify);
+	printf("         [%s] vs [%s]: %d%s\n",
+		scratch, verify, ret,
+		(check_ret == -1)?" (expected to fail)":""
+		);
+	if(check_ret == -1) {
+		assert(strcmp(scratch, verify));
+	} else {
+		assert(strcmp(scratch, verify) == 0);
+	}
+}
+
 static void
 check_xer(int tofail, char *xmldata, long orig_value) {
 	INTEGER_t *st = 0;
@@ -117,6 +185,11 @@ main(int ac, char **av) {
 	uint8_t buf11[] = { 0x80, 0, 0, 0 };
 	uint8_t buf12[] = { 0x80, 0 };
 	uint8_t buf13[] = { 0x80 };
+	uint8_t buf14[] = { 0x00, 0x80, 0x00, 0x00 };
+	uint8_t buf15[] = { 0x00, 0x80, 0x00, 0x00, 0x00 };
+	uint8_t buf16[] = { 0x00, 0xff, 0xff, 0x00, 0x00 };
+
+#define	UCHECK(buf, val, ret)	check_unsigned(buf, sizeof(buf), val, ret)
 
 #define	CHECK(buf, val, ret)	check(buf, sizeof(buf), val, ret)
 
@@ -130,9 +203,13 @@ main(int ac, char **av) {
 	CHECK(buf8, 0x7F7E7D7C, 0);
 	CHECK(buf9, 0x7F7E7D7C, 0);
 	CHECK(buf10, 0x7F7E7D7C, 0);
+	UCHECK(buf10, 0x7F7E7D7C, 0);
 	CHECK(buf11, -2147483647-1, 0);	/* 0x80000000 */
 	CHECK(buf12, -32768, 0);
 	CHECK(buf13, -128, 0);
+	UCHECK(buf14, 0x800000, 0);
+	UCHECK(buf15, 0x80000000, 0);
+	UCHECK(buf16, 0xffff0000, 0);
 
 	check_xer(-1, "", 0);
 	check_xer(-1, "<INTEGER></INTEGER>", 0);