[VOL-3880] Correctly reporting software image status in OMCI Get
[VOL-3900] OMCI ONU Software Image Download

Change-Id: I8d91be832f3a89404d0af0dd98e6b53359e6a738
diff --git a/Makefile b/Makefile
index c07c301..a993f7f 100644
--- a/Makefile
+++ b/Makefile
@@ -77,7 +77,7 @@
 
 test: docs-lint test-unit test-bbr
 
-test-unit: clean local-omci-sim # @HELP Execute unit tests
+test-unit: clean local-omci-lib-go # @HELP Execute unit tests
 	@echo "Running unit tests..."
 	@mkdir -p ./tests/results
 	@${GO} test -mod=vendor -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
@@ -96,7 +96,7 @@
 	${GO} mod tidy
 	${GO} mod vendor
 
-docker-build: local-omci-sim local-protos# @HELP Build the BBSim docker container (contains BBSimCtl too)
+docker-build: local-omci-lib-go local-protos# @HELP Build the BBSim docker container (contains BBSimCtl too)
 	docker build \
 	  -t ${DOCKER_REGISTRY}${DOCKER_REPOSITORY}bbsim:${DOCKER_TAG} \
 	  -f build/package/Dockerfile .
@@ -180,10 +180,10 @@
     '
 
 ## Local Development Helpers
-local-omci-sim:
-ifdef LOCAL_OMCI_SIM
-	mkdir -p vendor/github.com/opencord/omci-sim/
-	cp -r ${LOCAL_OMCI_SIM}/* vendor/github.com/opencord/omci-sim/
+local-omci-lib-go:
+ifdef LOCAL_OMCI_LIB_GO
+	mkdir -p vendor/github.com/opencord/omci-lib-go
+	cp -r ${LOCAL_OMCI_LIB_GO}/* vendor/github.com/opencord/omci-lib-go
 endif
 
 local-protos: ## Copies a local version of the voltha-protos dependency into the vendor directory
@@ -203,7 +203,7 @@
 	@rm -rf tools/bin
 	@rm -rf release/*
 
-build-bbr: local-omci-sim local-protos
+build-bbr: local-omci-lib-go local-protos
 	@go build -mod vendor \
 	  -ldflags "-w -X main.buildTime=$(shell date +%Y/%m/%d-%H:%M:%S) \
 	    -X main.commitHash=$(shell git log --pretty=format:%H -n 1) \
diff --git a/api/bbsim/bbsim.pb.go b/api/bbsim/bbsim.pb.go
index e9b3f56..fa00279 100644
--- a/api/bbsim/bbsim.pb.go
+++ b/api/bbsim/bbsim.pb.go
@@ -316,17 +316,21 @@
 }
 
 type ONU struct {
-	ID                   int32      `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
-	SerialNumber         string     `protobuf:"bytes,2,opt,name=SerialNumber,proto3" json:"SerialNumber,omitempty"`
-	OperState            string     `protobuf:"bytes,3,opt,name=OperState,proto3" json:"OperState,omitempty"`
-	InternalState        string     `protobuf:"bytes,4,opt,name=InternalState,proto3" json:"InternalState,omitempty"`
-	PonPortID            int32      `protobuf:"varint,5,opt,name=PonPortID,proto3" json:"PonPortID,omitempty"`
-	HwAddress            string     `protobuf:"bytes,8,opt,name=HwAddress,proto3" json:"HwAddress,omitempty"`
-	PortNo               int32      `protobuf:"varint,9,opt,name=PortNo,proto3" json:"PortNo,omitempty"`
-	Services             []*Service `protobuf:"bytes,10,rep,name=services,proto3" json:"services,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
-	XXX_unrecognized     []byte     `json:"-"`
-	XXX_sizecache        int32      `json:"-"`
+	ID                            int32      `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
+	SerialNumber                  string     `protobuf:"bytes,2,opt,name=SerialNumber,proto3" json:"SerialNumber,omitempty"`
+	OperState                     string     `protobuf:"bytes,3,opt,name=OperState,proto3" json:"OperState,omitempty"`
+	InternalState                 string     `protobuf:"bytes,4,opt,name=InternalState,proto3" json:"InternalState,omitempty"`
+	PonPortID                     int32      `protobuf:"varint,5,opt,name=PonPortID,proto3" json:"PonPortID,omitempty"`
+	HwAddress                     string     `protobuf:"bytes,8,opt,name=HwAddress,proto3" json:"HwAddress,omitempty"`
+	PortNo                        int32      `protobuf:"varint,9,opt,name=PortNo,proto3" json:"PortNo,omitempty"`
+	Services                      []*Service `protobuf:"bytes,10,rep,name=services,proto3" json:"services,omitempty"`
+	ImageSoftwareExpectedSections int32      `protobuf:"varint,11,opt,name=ImageSoftwareExpectedSections,proto3" json:"ImageSoftwareExpectedSections,omitempty"`
+	ImageSoftwareReceivedSections int32      `protobuf:"varint,12,opt,name=ImageSoftwareReceivedSections,proto3" json:"ImageSoftwareReceivedSections,omitempty"`
+	ActiveImageEntityId           int32      `protobuf:"varint,13,opt,name=ActiveImageEntityId,proto3" json:"ActiveImageEntityId,omitempty"`
+	CommittedImageEntityId        int32      `protobuf:"varint,14,opt,name=CommittedImageEntityId,proto3" json:"CommittedImageEntityId,omitempty"`
+	XXX_NoUnkeyedLiteral          struct{}   `json:"-"`
+	XXX_unrecognized              []byte     `json:"-"`
+	XXX_sizecache                 int32      `json:"-"`
 }
 
 func (m *ONU) Reset()         { *m = ONU{} }
@@ -410,6 +414,34 @@
 	return nil
 }
 
+func (m *ONU) GetImageSoftwareExpectedSections() int32 {
+	if m != nil {
+		return m.ImageSoftwareExpectedSections
+	}
+	return 0
+}
+
+func (m *ONU) GetImageSoftwareReceivedSections() int32 {
+	if m != nil {
+		return m.ImageSoftwareReceivedSections
+	}
+	return 0
+}
+
+func (m *ONU) GetActiveImageEntityId() int32 {
+	if m != nil {
+		return m.ActiveImageEntityId
+	}
+	return 0
+}
+
+func (m *ONU) GetCommittedImageEntityId() int32 {
+	if m != nil {
+		return m.CommittedImageEntityId
+	}
+	return 0
+}
+
 type Service struct {
 	Name                 string   `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
 	HwAddress            string   `protobuf:"bytes,2,opt,name=HwAddress,proto3" json:"HwAddress,omitempty"`
@@ -1298,106 +1330,112 @@
 func init() { proto.RegisterFile("api/bbsim/bbsim.proto", fileDescriptor_ef7750073d18011b) }
 
 var fileDescriptor_ef7750073d18011b = []byte{
-	// 1579 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcb, 0x6e, 0xdb, 0x46,
-	0x17, 0xd6, 0xc5, 0xba, 0x1d, 0x59, 0x32, 0x3d, 0x89, 0x1d, 0xc1, 0xf1, 0xff, 0x47, 0xe0, 0x9f,
-	0xbf, 0x70, 0x82, 0xc6, 0x69, 0xec, 0x5e, 0x92, 0x25, 0x2d, 0xd1, 0x0a, 0x6b, 0x99, 0x24, 0x86,
-	0x92, 0x83, 0xac, 0x08, 0x5a, 0x1a, 0xdb, 0x02, 0x28, 0x52, 0x21, 0x29, 0x1b, 0x7e, 0x80, 0x3e,
-	0x43, 0xf7, 0x7d, 0xa2, 0x3e, 0x41, 0x77, 0xed, 0xbe, 0x0f, 0x50, 0xa0, 0x98, 0x0b, 0x29, 0xd2,
-	0x92, 0x5b, 0xa7, 0x9b, 0x6e, 0x84, 0x39, 0xdf, 0xb9, 0x9f, 0x39, 0x3c, 0x67, 0x04, 0x5b, 0xce,
-	0x6c, 0xf2, 0xfa, 0xfc, 0x3c, 0x9c, 0x4c, 0xf9, 0xef, 0xfe, 0x2c, 0xf0, 0x23, 0x1f, 0x95, 0x18,
-	0xb1, 0xf3, 0xf4, 0xda, 0x77, 0xa3, 0x2b, 0xc7, 0x66, 0x60, 0xf8, 0xda, 0x9f, 0x11, 0xcf, 0x77,
-	0x23, 0x2e, 0xb3, 0xd3, 0xce, 0x32, 0x23, 0x32, 0xba, 0xa2, 0xe7, 0x8b, 0x89, 0x4b, 0xb8, 0x84,
-	0xfc, 0x1d, 0x54, 0x4c, 0x43, 0x37, 0xfd, 0x20, 0x42, 0x4d, 0x28, 0x68, 0xdd, 0x56, 0xbe, 0x9d,
-	0xdf, 0x2b, 0xe1, 0x82, 0xd6, 0x45, 0xbb, 0x50, 0x33, 0x66, 0x24, 0xb0, 0x22, 0x27, 0x22, 0xad,
-	0x42, 0x3b, 0xbf, 0x57, 0xc3, 0x0b, 0x80, 0x2a, 0xea, 0xba, 0xf6, 0x0f, 0x14, 0x7f, 0xcd, 0x43,
-	0xd1, 0x70, 0x97, 0xb5, 0x64, 0x58, 0xb7, 0x48, 0x30, 0x71, 0x5c, 0x7d, 0x3e, 0x3d, 0x27, 0x81,
-	0x50, 0xcc, 0x60, 0x59, 0xcb, 0xc5, 0x3b, 0x96, 0xd1, 0x73, 0x68, 0x68, 0x5e, 0x44, 0x02, 0xcf,
-	0x71, 0xb9, 0xc4, 0x1a, 0x93, 0xc8, 0x82, 0xcc, 0xaf, 0xd9, 0xaa, 0x30, 0x56, 0x41, 0x33, 0xd1,
-	0x4b, 0xa8, 0x8a, 0x44, 0xc2, 0x56, 0xa9, 0x5d, 0xdc, 0xab, 0x1f, 0x34, 0xf7, 0x79, 0x9d, 0x05,
-	0x8c, 0x13, 0x3e, 0x95, 0x15, 0xd5, 0x0a, 0x5b, 0xe5, 0x8c, 0xac, 0x80, 0x71, 0xc2, 0x97, 0xff,
-	0xa0, 0x79, 0xea, 0xc3, 0x7f, 0x2d, 0xcf, 0x5d, 0xa8, 0x99, 0xbe, 0x47, 0x63, 0xd1, 0xba, 0xad,
-	0x12, 0x73, 0xbf, 0x00, 0x28, 0xf7, 0xfd, 0x8d, 0x32, 0x1e, 0x07, 0x24, 0x0c, 0x5b, 0x55, 0xee,
-	0x21, 0x01, 0xd0, 0x36, 0x94, 0xa9, 0x9c, 0xee, 0xb7, 0x6a, 0x4c, 0x51, 0x50, 0x34, 0xff, 0x90,
-	0x04, 0xd7, 0x93, 0x11, 0x09, 0x5b, 0x90, 0xc9, 0xdf, 0xe2, 0x30, 0x4e, 0xf8, 0xf2, 0xef, 0x05,
-	0xa8, 0x08, 0x14, 0x21, 0x58, 0xd3, 0x9d, 0x29, 0x61, 0x55, 0xa8, 0x61, 0x76, 0xce, 0x46, 0x50,
-	0xb8, 0x1b, 0xc1, 0x63, 0x28, 0x19, 0xde, 0xdc, 0xf2, 0x44, 0xf6, 0x9c, 0xa0, 0x76, 0xac, 0x81,
-	0x73, 0xc9, 0x12, 0x2e, 0x61, 0x76, 0xa6, 0x58, 0x87, 0x62, 0x3c, 0x45, 0x76, 0x46, 0xff, 0x05,
-	0xd0, 0x09, 0x19, 0x87, 0xaa, 0x33, 0xf3, 0xdd, 0x56, 0xb9, 0x9d, 0xdf, 0xab, 0xe2, 0x14, 0x42,
-	0x7d, 0x33, 0xaa, 0x7b, 0x35, 0x9a, 0xb1, 0x56, 0xa8, 0xe2, 0x05, 0x90, 0x70, 0xb5, 0xcb, 0xe9,
-	0x8c, 0xd5, 0x26, 0xe6, 0x52, 0x00, 0xb5, 0xa0, 0xd2, 0x23, 0x53, 0x5a, 0x10, 0x51, 0x9c, 0x98,
-	0xa4, 0x5e, 0x99, 0x79, 0x7e, 0x29, 0xc0, 0x02, 0x4f, 0x21, 0xd4, 0x2e, 0xb5, 0xcf, 0xd9, 0x75,
-	0x9e, 0x71, 0x02, 0x2c, 0xdf, 0xea, 0xfa, 0x3d, 0xb7, 0xaa, 0xf5, 0x4e, 0x4d, 0x2e, 0xd1, 0xe0,
-	0x36, 0x12, 0x40, 0x76, 0xe0, 0xb1, 0xa1, 0x0f, 0x07, 0x81, 0x73, 0x71, 0x31, 0x19, 0x59, 0xa3,
-	0x2b, 0x32, 0x9e, 0xbb, 0x24, 0x08, 0x91, 0x06, 0x1b, 0x11, 0x05, 0x17, 0x10, 0xbb, 0x8a, 0xfa,
-	0xc1, 0xb3, 0xfd, 0xcc, 0x4c, 0x58, 0xd2, 0xc4, 0x77, 0xf5, 0xe4, 0x3d, 0x58, 0x33, 0xf4, 0x61,
-	0x88, 0xda, 0x50, 0x9a, 0x44, 0x64, 0x4a, 0x0d, 0xd1, 0x3e, 0x00, 0xd1, 0x07, 0x86, 0x3e, 0xc4,
-	0x9c, 0x21, 0x7f, 0x05, 0x55, 0x71, 0xff, 0x21, 0x7a, 0x9e, 0x95, 0xbe, 0xdb, 0x35, 0x89, 0x06,
-	0x50, 0x7d, 0xf2, 0x69, 0x4e, 0xc2, 0x68, 0xe9, 0x43, 0xc9, 0x2f, 0x7f, 0x28, 0xf2, 0x4b, 0x00,
-	0xd3, 0xd0, 0x63, 0x8d, 0x54, 0xcb, 0x8f, 0x99, 0x78, 0x63, 0xd1, 0xf2, 0x63, 0xf9, 0x97, 0x22,
-	0xd4, 0x14, 0xd7, 0x09, 0xa6, 0x83, 0xdb, 0x19, 0x91, 0x7f, 0x2e, 0x42, 0x89, 0x1e, 0x42, 0x54,
-	0x81, 0x62, 0xdf, 0xb0, 0xa4, 0x1c, 0x6a, 0x02, 0x74, 0x3f, 0x6a, 0x7a, 0xcf, 0xee, 0x29, 0x96,
-	0x29, 0xe5, 0x51, 0x03, 0x6a, 0x86, 0x3e, 0xb4, 0x95, 0xbe, 0x82, 0x4f, 0xa5, 0x02, 0x7a, 0x02,
-	0x8f, 0x28, 0x69, 0x0d, 0x14, 0x3c, 0x18, 0x9a, 0xf6, 0xb1, 0xa2, 0xf5, 0x87, 0x58, 0x95, 0x8a,
-	0x68, 0x1b, 0x10, 0x63, 0x68, 0x3d, 0x5d, 0xe9, 0xdb, 0x5d, 0xb5, 0x87, 0x95, 0xae, 0x2a, 0xad,
-	0xc5, 0x0a, 0x5d, 0xac, 0x1d, 0x0f, 0x6c, 0xe3, 0xd8, 0xfe, 0xa0, 0xe9, 0x5d, 0xe3, 0x83, 0x54,
-	0x42, 0xbb, 0xd0, 0xa2, 0x8c, 0xbe, 0x61, 0x59, 0x14, 0x37, 0x4e, 0x3b, 0x9a, 0xdd, 0x79, 0xaf,
-	0xe8, 0xba, 0xda, 0x97, 0xca, 0x89, 0x1f, 0x66, 0xce, 0x4a, 0xfc, 0x54, 0xd0, 0x0b, 0xf8, 0x3f,
-	0x65, 0x0c, 0xb0, 0xa2, 0x5b, 0xa7, 0x9a, 0x65, 0x69, 0x86, 0x6e, 0x6b, 0xfa, 0x40, 0xc5, 0xc7,
-	0x2a, 0x56, 0xf5, 0x8e, 0x6a, 0x7f, 0x50, 0xb0, 0xae, 0xe9, 0x3d, 0xa9, 0x8a, 0x76, 0x60, 0x9b,
-	0x85, 0xde, 0x19, 0x68, 0x67, 0xca, 0x80, 0x0a, 0xc6, 0x66, 0x6a, 0xa8, 0xc5, 0x9a, 0xc4, 0x36,
-	0xb1, 0xd1, 0x51, 0x2d, 0x8b, 0xe6, 0xab, 0x62, 0x6c, 0x60, 0x09, 0x50, 0x1b, 0x76, 0xd3, 0x71,
-	0x9d, 0xa8, 0x1f, 0x6d, 0xeb, 0xa3, 0xde, 0x49, 0x74, 0xeb, 0x68, 0x0b, 0x36, 0xa9, 0x84, 0x36,
-	0x18, 0xda, 0xa6, 0xa1, 0xd3, 0x5a, 0x0c, 0x2c, 0x69, 0x1d, 0x6d, 0x42, 0x23, 0xa9, 0x14, 0x55,
-	0x97, 0x1a, 0x77, 0xa1, 0x23, 0xa9, 0x19, 0x27, 0x16, 0x43, 0x66, 0xc7, 0xa6, 0x59, 0x48, 0x1b,
-	0x71, 0x3d, 0x32, 0x8c, 0x8e, 0x88, 0x4a, 0x42, 0x08, 0x9a, 0x69, 0xee, 0xb1, 0x26, 0x6d, 0xa2,
-	0x47, 0xb0, 0x91, 0xc6, 0x94, 0x53, 0x4d, 0x42, 0xf2, 0x5b, 0x68, 0xb2, 0xfb, 0x35, 0x9d, 0xc0,
-	0x99, 0x92, 0x88, 0x04, 0x48, 0x82, 0xe2, 0x09, 0xb9, 0x15, 0x9d, 0x43, 0x8f, 0x74, 0xae, 0x9c,
-	0x39, 0xee, 0x3c, 0xde, 0x4b, 0x9c, 0x90, 0x7f, 0xca, 0x33, 0x7b, 0x4c, 0x3b, 0xd5, 0x4c, 0x49,
-	0xb7, 0x08, 0x0b, 0x0b, 0xe0, 0x41, 0x53, 0x7c, 0x1b, 0xca, 0xf4, 0xb3, 0x9c, 0x87, 0x62, 0x88,
-	0x09, 0x0a, 0x7d, 0x03, 0x90, 0x84, 0x18, 0xb6, 0xd6, 0xd8, 0x17, 0xb1, 0x25, 0xbe, 0x88, 0x6c,
-	0x02, 0x38, 0x25, 0x28, 0x7f, 0x82, 0x0d, 0xa3, 0x3f, 0xc8, 0xc4, 0xd8, 0x86, 0x3a, 0x1b, 0x0f,
-	0x17, 0xce, 0x88, 0x88, 0x25, 0xd3, 0xc0, 0x69, 0x28, 0x99, 0x2a, 0x94, 0x64, 0x99, 0x14, 0x52,
-	0x53, 0x25, 0x06, 0xef, 0x8b, 0x54, 0xfe, 0x21, 0x0f, 0x8d, 0x33, 0x12, 0x84, 0x13, 0xdf, 0x13,
-	0x39, 0xb5, 0xa0, 0x72, 0xcd, 0x01, 0x51, 0x93, 0x98, 0xa4, 0xf5, 0x3a, 0x9f, 0x4f, 0xdc, 0xf1,
-	0x60, 0x32, 0x4d, 0xb6, 0x7e, 0x02, 0xd0, 0xd9, 0x38, 0xf2, 0xa7, 0xd3, 0x49, 0xf4, 0xde, 0x09,
-	0xaf, 0x84, 0x97, 0x14, 0x42, 0xb5, 0x2f, 0x27, 0x91, 0x08, 0x82, 0xef, 0xb3, 0x05, 0x20, 0xbf,
-	0x85, 0x6a, 0xdf, 0xbf, 0xec, 0x93, 0x6b, 0xe2, 0xd2, 0x1b, 0x74, 0xe9, 0x41, 0xf8, 0xe7, 0x04,
-	0xcd, 0x60, 0xe4, 0xb8, 0xae, 0xb8, 0x89, 0x2a, 0x16, 0x94, 0xac, 0x42, 0x15, 0x93, 0x70, 0xe6,
-	0x7b, 0x21, 0x41, 0xcf, 0xa0, 0x1e, 0x32, 0x7b, 0xf6, 0xc8, 0x1f, 0x13, 0xb1, 0x92, 0x81, 0x43,
-	0x1d, 0x7f, 0x4c, 0x68, 0x72, 0x53, 0x12, 0x86, 0xce, 0x65, 0x9c, 0x40, 0x4c, 0xca, 0x3f, 0xe6,
-	0xa1, 0x4e, 0xa7, 0x7f, 0x5c, 0xf8, 0x17, 0x50, 0x36, 0xbc, 0x39, 0x26, 0x9f, 0xc4, 0x1c, 0xdd,
-	0x4c, 0x8d, 0x3f, 0x2e, 0x82, 0x85, 0x00, 0x7a, 0x07, 0xeb, 0xd6, 0xfc, 0x5c, 0x19, 0x45, 0x13,
-	0xdf, 0x3b, 0x73, 0x5c, 0x66, 0xb9, 0x99, 0xdc, 0x77, 0xc2, 0x62, 0xb3, 0x08, 0x67, 0x44, 0x69,
-	0x93, 0xf5, 0x02, 0x7f, 0x3e, 0x8b, 0xb7, 0x24, 0x2f, 0x5b, 0x06, 0x93, 0x4f, 0xa0, 0x74, 0xec,
-	0xfa, 0x37, 0x21, 0xfa, 0x0f, 0xc0, 0x85, 0xeb, 0xdf, 0xd8, 0x23, 0x7f, 0xee, 0x45, 0xf1, 0xf4,
-	0xa3, 0x48, 0x87, 0x02, 0xe8, 0x7f, 0x50, 0xa2, 0x04, 0x5d, 0xb5, 0xb4, 0xdf, 0x1a, 0xfb, 0xf1,
-	0x4b, 0x91, 0x6a, 0x63, 0xce, 0x93, 0x9f, 0x41, 0x85, 0xde, 0x96, 0x3f, 0x8f, 0x68, 0x99, 0xc7,
-	0xc4, 0x75, 0x6e, 0x85, 0x25, 0x4e, 0xc8, 0x15, 0x28, 0xa9, 0xd3, 0x59, 0x74, 0xfb, 0xf2, 0x0d,
-	0x34, 0xb3, 0xa1, 0xa3, 0x2a, 0xac, 0x7d, 0x6f, 0x68, 0xba, 0x94, 0x43, 0x35, 0x28, 0xf5, 0x55,
-	0xe5, 0x4c, 0x95, 0xf2, 0x08, 0xa0, 0x4c, 0xc1, 0xb3, 0x43, 0xa9, 0x70, 0xf0, 0x1b, 0x40, 0xe9,
-	0xe8, 0xc8, 0x9a, 0x4c, 0xd1, 0x6b, 0xa8, 0x88, 0xae, 0x42, 0xeb, 0xa2, 0x0e, 0xcc, 0xea, 0xce,
-	0x63, 0x41, 0x65, 0x7a, 0x4e, 0xce, 0xa1, 0x37, 0x50, 0xb7, 0x48, 0x94, 0xb4, 0xc0, 0x86, 0x10,
-	0x8b, 0x81, 0x9d, 0xbb, 0x80, 0x9c, 0x43, 0xcf, 0xa1, 0xdc, 0x23, 0x11, 0x7d, 0x68, 0x66, 0x5d,
-	0x24, 0x8b, 0xca, 0x8d, 0xe4, 0x1c, 0x7a, 0x05, 0x60, 0xfa, 0x37, 0x24, 0xf0, 0xbd, 0x65, 0xc9,
-	0xd8, 0x68, 0xdc, 0x3f, 0x72, 0x0e, 0xed, 0x43, 0xdd, 0xba, 0x9a, 0x47, 0x63, 0xff, 0xe6, 0x61,
-	0xf2, 0x5f, 0x42, 0x0d, 0x93, 0x73, 0xdf, 0x8f, 0x1e, 0x24, 0x4d, 0x6b, 0x1a, 0xf9, 0xb3, 0x4b,
-	0x6c, 0x76, 0xe8, 0x62, 0x24, 0xc1, 0xdf, 0xab, 0x1c, 0xc0, 0x86, 0x15, 0x39, 0x41, 0xf4, 0x39,
-	0x3a, 0xdf, 0xc2, 0x26, 0x26, 0xe1, 0x1d, 0xad, 0x78, 0x23, 0x8b, 0xeb, 0x5f, 0xa5, 0xf7, 0x82,
-	0x57, 0x54, 0x1f, 0xa2, 0xe5, 0x6e, 0xdf, 0x49, 0xed, 0x7f, 0x39, 0x87, 0xbe, 0xa0, 0x6f, 0xa4,
-	0x88, 0xbd, 0x13, 0xb2, 0xe1, 0xd4, 0x17, 0x62, 0x21, 0xaf, 0x67, 0x8f, 0x44, 0xc9, 0x2b, 0x61,
-	0x75, 0xe8, 0x31, 0x9b, 0x85, 0xde, 0xa4, 0x76, 0xbd, 0x79, 0xa2, 0xb2, 0x22, 0x94, 0x15, 0x7a,
-	0x87, 0xa9, 0x7b, 0x5b, 0x1d, 0xff, 0x3d, 0xb5, 0x15, 0x4a, 0x8a, 0xeb, 0xae, 0x48, 0x66, 0x85,
-	0xce, 0x3b, 0xd8, 0x4c, 0x39, 0x0a, 0x0d, 0xcf, 0x34, 0xf4, 0xc4, 0xdd, 0xe2, 0xa5, 0xb2, 0xda,
-	0x5d, 0xd2, 0x8a, 0x0f, 0x0e, 0xf1, 0x0d, 0x34, 0x85, 0xce, 0x83, 0x23, 0x7c, 0x0b, 0xd2, 0xc2,
-	0xcd, 0x67, 0x05, 0xf8, 0x35, 0xac, 0x8b, 0xbe, 0xe1, 0x8f, 0xe8, 0x87, 0x85, 0x78, 0x08, 0x75,
-	0xa1, 0xc5, 0xde, 0xd6, 0x0f, 0x53, 0x3a, 0x82, 0x2d, 0x8b, 0xdd, 0x33, 0xdb, 0x76, 0x9a, 0x37,
-	0x9e, 0x8c, 0x1c, 0x3a, 0x69, 0xd0, 0xf6, 0x42, 0x3d, 0xbd, 0x08, 0xff, 0xc2, 0x86, 0x1b, 0xdd,
-	0x6b, 0x23, 0xbb, 0x4c, 0x57, 0xd9, 0x78, 0x05, 0xd5, 0x1e, 0x89, 0xf8, 0x7c, 0x5d, 0x11, 0x79,
-	0x5c, 0x6c, 0x26, 0xc0, 0x6a, 0xbb, 0xd1, 0xb9, 0x72, 0xbc, 0x4b, 0x42, 0x57, 0x05, 0x7f, 0xaf,
-	0x23, 0x21, 0x92, 0x5a, 0x1e, 0xab, 0x1c, 0x9d, 0xc0, 0x13, 0xde, 0xd8, 0xcb, 0x6f, 0xf7, 0x15,
-	0x7e, 0x9f, 0x2e, 0xa0, 0x25, 0x79, 0x39, 0x77, 0x5e, 0x66, 0x7f, 0xed, 0x0f, 0xff, 0x0c, 0x00,
-	0x00, 0xff, 0xff, 0x96, 0xa7, 0x23, 0x49, 0x39, 0x10, 0x00, 0x00,
+	// 1668 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xcd, 0x72, 0xdb, 0xc8,
+	0x11, 0xe6, 0x8f, 0xf8, 0xd7, 0x14, 0x29, 0x68, 0x6c, 0x6b, 0x51, 0x5a, 0x6f, 0xcc, 0x42, 0x9c,
+	0x94, 0xec, 0xca, 0xca, 0x6b, 0x3b, 0xd9, 0x78, 0x8f, 0x30, 0x09, 0xd1, 0x88, 0x29, 0x00, 0x35,
+	0x20, 0xe5, 0xf2, 0x09, 0x05, 0x91, 0x23, 0x0a, 0x55, 0x20, 0x40, 0x03, 0x43, 0x29, 0x7a, 0x80,
+	0x3c, 0x43, 0xee, 0x79, 0xa2, 0x3c, 0x41, 0x6e, 0xc9, 0x3d, 0x95, 0x17, 0x48, 0xcd, 0x60, 0x00,
+	0x02, 0x24, 0xb5, 0x91, 0x73, 0xd9, 0x0b, 0x0b, 0xf3, 0x75, 0x7f, 0xdd, 0x3d, 0x3d, 0x3d, 0xdd,
+	0x53, 0x84, 0x27, 0xee, 0xd2, 0x7b, 0x75, 0x79, 0x19, 0x7b, 0x8b, 0xe4, 0xf7, 0x74, 0x19, 0x85,
+	0x34, 0x44, 0x35, 0xbe, 0x38, 0xfe, 0xf6, 0x26, 0xf4, 0xe9, 0xb5, 0xeb, 0x70, 0x30, 0x7e, 0x15,
+	0x2e, 0x49, 0x10, 0xfa, 0x34, 0xd1, 0x39, 0xee, 0x15, 0x85, 0x94, 0x4c, 0xaf, 0xd9, 0xf7, 0x95,
+	0xe7, 0x93, 0x44, 0x43, 0xf9, 0x23, 0x34, 0x2c, 0xd3, 0xb0, 0xc2, 0x88, 0xa2, 0x2e, 0x54, 0xf4,
+	0x81, 0x5c, 0xee, 0x95, 0x4f, 0x6a, 0xb8, 0xa2, 0x0f, 0xd0, 0x53, 0x68, 0x99, 0x4b, 0x12, 0xd9,
+	0xd4, 0xa5, 0x44, 0xae, 0xf4, 0xca, 0x27, 0x2d, 0xbc, 0x06, 0x18, 0xd1, 0x30, 0xf4, 0xff, 0x83,
+	0xf8, 0xcf, 0x32, 0x54, 0x4d, 0x7f, 0x9b, 0xa5, 0xc0, 0xbe, 0x4d, 0x22, 0xcf, 0xf5, 0x8d, 0xd5,
+	0xe2, 0x92, 0x44, 0x82, 0x58, 0xc0, 0x8a, 0x96, 0xab, 0x1b, 0x96, 0xd1, 0x73, 0xe8, 0xe8, 0x01,
+	0x25, 0x51, 0xe0, 0xfa, 0x89, 0xc6, 0x1e, 0xd7, 0x28, 0x82, 0xdc, 0xaf, 0x25, 0x37, 0xb8, 0xa8,
+	0xa2, 0x5b, 0xe8, 0x25, 0x34, 0xc5, 0x46, 0x62, 0xb9, 0xd6, 0xab, 0x9e, 0xb4, 0xdf, 0x74, 0x4f,
+	0x93, 0x3c, 0x0b, 0x18, 0x67, 0x72, 0xa6, 0x2b, 0xb2, 0x15, 0xcb, 0xf5, 0x82, 0xae, 0x80, 0x71,
+	0x26, 0x57, 0xfe, 0x53, 0x85, 0xaa, 0x69, 0x4c, 0x7e, 0xb1, 0x7d, 0x3e, 0x85, 0x96, 0x15, 0x06,
+	0x2c, 0x16, 0x7d, 0x20, 0xd7, 0xb8, 0xfb, 0x35, 0xc0, 0xa4, 0x1f, 0x6e, 0xd5, 0xd9, 0x2c, 0x22,
+	0x71, 0x2c, 0x37, 0x13, 0x0f, 0x19, 0x80, 0x8e, 0xa0, 0xce, 0xf4, 0x8c, 0x50, 0x6e, 0x71, 0xa2,
+	0x58, 0xb1, 0xfd, 0xc7, 0x24, 0xba, 0xf1, 0xa6, 0x24, 0x96, 0xa1, 0xb0, 0x7f, 0x3b, 0x81, 0x71,
+	0x26, 0x47, 0x03, 0xf8, 0x4e, 0x5f, 0xb8, 0x73, 0x62, 0x87, 0x57, 0xf4, 0xd6, 0x8d, 0x88, 0xf6,
+	0xe7, 0x25, 0x99, 0x52, 0x32, 0xb3, 0xc9, 0x94, 0x7a, 0x61, 0x10, 0xcb, 0x6d, 0x6e, 0xfa, 0xe7,
+	0x95, 0xb6, 0xac, 0x60, 0x32, 0x25, 0xde, 0x4d, 0xce, 0xca, 0xfe, 0x0e, 0x2b, 0x9b, 0x4a, 0xe8,
+	0x07, 0x78, 0xa4, 0x4e, 0xa9, 0x77, 0x43, 0xb8, 0x9a, 0x16, 0x50, 0x8f, 0xde, 0xe9, 0x33, 0xb9,
+	0xc3, 0xb9, 0xbb, 0x44, 0xe8, 0x47, 0x38, 0xea, 0x87, 0x8b, 0x85, 0x47, 0x29, 0x99, 0x15, 0x49,
+	0x5d, 0x4e, 0xba, 0x47, 0xaa, 0xfc, 0xbb, 0x02, 0x0d, 0x91, 0x0b, 0x84, 0x60, 0xcf, 0x70, 0x17,
+	0x84, 0x9f, 0x7d, 0x0b, 0xf3, 0xef, 0x62, 0xde, 0x2b, 0x9b, 0x79, 0x7f, 0x0c, 0x35, 0x33, 0x58,
+	0xd9, 0x81, 0x38, 0xf3, 0x64, 0xc1, 0xec, 0xd8, 0x63, 0x77, 0xce, 0x8f, 0xb9, 0x86, 0xf9, 0x37,
+	0xc3, 0xfa, 0x0c, 0x4b, 0x0e, 0x96, 0x7f, 0xa3, 0x5f, 0x01, 0x18, 0x84, 0xcc, 0x62, 0xcd, 0x5d,
+	0x86, 0xbe, 0x5c, 0xef, 0x95, 0x4f, 0x9a, 0x38, 0x87, 0x30, 0xdf, 0x7c, 0x35, 0xb8, 0x9e, 0x2e,
+	0xf9, 0x05, 0x68, 0xe2, 0x35, 0x90, 0x49, 0xf5, 0xf9, 0x62, 0xc9, 0x2b, 0x22, 0x95, 0x32, 0x00,
+	0xc9, 0xd0, 0x18, 0x92, 0x05, 0x2b, 0x03, 0x51, 0x12, 0xe9, 0x92, 0x79, 0xe5, 0xe6, 0x93, 0x52,
+	0x04, 0x1e, 0x78, 0x0e, 0x61, 0x76, 0x99, 0xfd, 0x44, 0xdc, 0x4e, 0x76, 0x9c, 0x01, 0xdb, 0xb5,
+	0xbc, 0x7f, 0x4f, 0x2d, 0xeb, 0xc3, 0x73, 0x2b, 0xd1, 0xe8, 0x24, 0x36, 0x32, 0x40, 0x71, 0xe1,
+	0xb1, 0x69, 0x4c, 0xc6, 0x91, 0x7b, 0x75, 0xe5, 0x4d, 0xed, 0xe9, 0x35, 0x99, 0xad, 0x7c, 0x12,
+	0xc5, 0x48, 0x87, 0x03, 0xca, 0xc0, 0x35, 0xc4, 0x8f, 0xa2, 0xfd, 0xe6, 0xd9, 0x69, 0xa1, 0x13,
+	0x6e, 0x31, 0xf1, 0x26, 0x4f, 0x39, 0x81, 0x3d, 0xd3, 0x98, 0xc4, 0xa8, 0x07, 0x35, 0x8f, 0x92,
+	0x05, 0x33, 0xc4, 0xaa, 0x1f, 0x44, 0xf5, 0x9b, 0xc6, 0x04, 0x27, 0x02, 0xe5, 0x07, 0x68, 0xda,
+	0xe9, 0x15, 0x78, 0x5e, 0xd4, 0xde, 0xbc, 0x2b, 0x19, 0x03, 0x18, 0x9f, 0x7c, 0x59, 0x91, 0x98,
+	0x6e, 0xb5, 0x87, 0xf2, 0x76, 0x7b, 0x50, 0x5e, 0x02, 0x58, 0xa6, 0x91, 0x32, 0x72, 0x17, 0x7d,
+	0xc6, 0xd5, 0x3b, 0xeb, 0x8b, 0x3e, 0x53, 0xfe, 0x51, 0x85, 0x96, 0xea, 0xbb, 0xd1, 0x62, 0x7c,
+	0xb7, 0x24, 0xca, 0xdf, 0xab, 0x50, 0x63, 0x1f, 0x31, 0x6a, 0x40, 0x75, 0x64, 0xda, 0x52, 0x09,
+	0x75, 0x01, 0x06, 0x9f, 0x75, 0x63, 0xe8, 0x0c, 0x55, 0xdb, 0x92, 0xca, 0xa8, 0x03, 0x2d, 0xd3,
+	0x98, 0x38, 0xea, 0x48, 0xc5, 0xe7, 0x52, 0x05, 0x7d, 0x03, 0x8f, 0xd8, 0xd2, 0x1e, 0xab, 0x78,
+	0x3c, 0xb1, 0x9c, 0x33, 0x55, 0x1f, 0x4d, 0xb0, 0x26, 0x55, 0xd1, 0x11, 0x20, 0x2e, 0xd0, 0x87,
+	0x86, 0x3a, 0x72, 0x06, 0xda, 0x10, 0xab, 0x03, 0x4d, 0xda, 0x4b, 0x09, 0x03, 0xac, 0x9f, 0x8d,
+	0x1d, 0xf3, 0xcc, 0xf9, 0xa4, 0x1b, 0x03, 0xf3, 0x93, 0x54, 0x43, 0x4f, 0x41, 0x66, 0x82, 0x91,
+	0x69, 0xdb, 0x0c, 0x37, 0xcf, 0xfb, 0xba, 0xd3, 0xff, 0xa0, 0x1a, 0x86, 0x36, 0x92, 0xea, 0x99,
+	0x1f, 0x6e, 0xce, 0xce, 0xfc, 0x34, 0xd0, 0x0b, 0xf8, 0x0d, 0x13, 0x8c, 0xb1, 0x6a, 0xd8, 0xe7,
+	0xba, 0x6d, 0xeb, 0xa6, 0xe1, 0xe8, 0xc6, 0x58, 0xc3, 0x67, 0x1a, 0xd6, 0x8c, 0xbe, 0xe6, 0x7c,
+	0x52, 0xb1, 0xa1, 0x1b, 0x43, 0xa9, 0x89, 0x8e, 0xe1, 0x88, 0x87, 0xde, 0x1f, 0xeb, 0x17, 0xea,
+	0x98, 0x29, 0xa6, 0x66, 0x5a, 0x48, 0xe6, 0x45, 0xe2, 0x58, 0xd8, 0xec, 0x6b, 0xb6, 0xcd, 0xf6,
+	0xab, 0x61, 0x6c, 0x62, 0x09, 0x50, 0x0f, 0x9e, 0xe6, 0xe3, 0xfa, 0xa8, 0x7d, 0x76, 0xec, 0xcf,
+	0x46, 0x3f, 0xe3, 0xb6, 0xd1, 0x13, 0x38, 0x64, 0x1a, 0xfa, 0x78, 0xe2, 0x58, 0xa6, 0xc1, 0x72,
+	0x31, 0xb6, 0xa5, 0x7d, 0x74, 0x08, 0x9d, 0x2c, 0x53, 0x8c, 0x2e, 0x75, 0x36, 0xa1, 0xf7, 0x52,
+	0x37, 0xdd, 0x58, 0x0a, 0x59, 0x7d, 0x87, 0xed, 0x42, 0x3a, 0x48, 0xf3, 0x51, 0x10, 0xf4, 0x45,
+	0x54, 0x12, 0x42, 0xd0, 0xcd, 0x4b, 0xcf, 0x74, 0xe9, 0x10, 0x3d, 0x82, 0x83, 0x3c, 0xa6, 0x9e,
+	0xeb, 0x12, 0x52, 0xde, 0x41, 0x97, 0x9f, 0xaf, 0xe5, 0x46, 0xee, 0x82, 0x50, 0x12, 0x21, 0x09,
+	0xaa, 0x1f, 0xc9, 0x9d, 0xa8, 0x1c, 0xf6, 0xc9, 0xfa, 0xca, 0x85, 0xeb, 0xaf, 0xd2, 0x69, 0x9c,
+	0x2c, 0x94, 0xbf, 0x95, 0xb9, 0x3d, 0xce, 0xce, 0x15, 0x53, 0x56, 0x2d, 0xc2, 0xc2, 0x1a, 0x78,
+	0xd0, 0xec, 0x3a, 0x82, 0x3a, 0xbb, 0x96, 0xab, 0x58, 0x34, 0x31, 0xb1, 0x42, 0x7f, 0x00, 0xc8,
+	0x42, 0x8c, 0xe5, 0x3d, 0x7e, 0x23, 0x9e, 0x88, 0x1b, 0x51, 0xdc, 0x00, 0xce, 0x29, 0x2a, 0x5f,
+	0xe0, 0xc0, 0x1c, 0x8d, 0x0b, 0x31, 0xf6, 0xa0, 0xcd, 0xdb, 0xc3, 0x95, 0x3b, 0x25, 0x62, 0xb4,
+	0x76, 0x70, 0x1e, 0xca, 0xba, 0x0a, 0x5b, 0xf2, 0x9d, 0x54, 0x72, 0x5d, 0x25, 0x05, 0xef, 0x8b,
+	0x54, 0xf9, 0x4b, 0x19, 0x3a, 0x17, 0x24, 0x8a, 0xbd, 0x30, 0x10, 0x7b, 0x92, 0xa1, 0x71, 0x93,
+	0x00, 0x22, 0x27, 0xe9, 0x92, 0xe5, 0xeb, 0x72, 0xe5, 0xf9, 0xb3, 0xb1, 0xb7, 0xc8, 0xde, 0x3a,
+	0x19, 0xc0, 0x7a, 0xe3, 0x94, 0xcf, 0x89, 0x0f, 0x6e, 0x7c, 0x2d, 0xbc, 0xe4, 0x10, 0xc6, 0x9e,
+	0x7b, 0x54, 0x04, 0x91, 0x4c, 0xf1, 0x35, 0xa0, 0xbc, 0x83, 0xe6, 0x28, 0x9c, 0x8f, 0xc8, 0x0d,
+	0xf1, 0xd9, 0x09, 0xfa, 0xec, 0x43, 0xf8, 0x4f, 0x16, 0x6c, 0x07, 0x53, 0xd7, 0xf7, 0xc5, 0x49,
+	0x34, 0xb1, 0x58, 0x29, 0x1a, 0x34, 0x31, 0x89, 0x97, 0x61, 0x10, 0x13, 0xf4, 0x0c, 0xda, 0x31,
+	0xb7, 0xe7, 0x4c, 0xc3, 0x19, 0x11, 0x0f, 0x11, 0x48, 0xa0, 0x7e, 0x38, 0x23, 0x6c, 0x73, 0x0b,
+	0x12, 0xc7, 0xee, 0x3c, 0xdd, 0x40, 0xba, 0x54, 0xfe, 0x5a, 0x86, 0x36, 0xeb, 0xfe, 0x69, 0xe2,
+	0x5f, 0x40, 0xdd, 0x0c, 0x56, 0x98, 0x7c, 0x11, 0x7d, 0xf4, 0x30, 0xd7, 0xfe, 0x12, 0x15, 0x2c,
+	0x14, 0xd0, 0x4f, 0xb0, 0x6f, 0xaf, 0x2e, 0x55, 0x3e, 0x7f, 0x2f, 0x5c, 0x9f, 0x5b, 0xee, 0x66,
+	0xe7, 0x9d, 0x89, 0x78, 0x2f, 0xc2, 0x05, 0x55, 0x56, 0x64, 0xc3, 0x28, 0x5c, 0x2d, 0xd3, 0x29,
+	0x99, 0xa4, 0xad, 0x80, 0x29, 0x1f, 0xa1, 0x76, 0xe6, 0x87, 0xb7, 0x31, 0xfa, 0x0e, 0xe0, 0xca,
+	0x0f, 0x6f, 0x9d, 0x69, 0xb8, 0x0a, 0x68, 0xda, 0xfd, 0x18, 0xd2, 0x67, 0x00, 0xfa, 0x35, 0xd4,
+	0xd8, 0x82, 0x8d, 0x5a, 0x56, 0x6f, 0x9d, 0xd3, 0xf4, 0x7d, 0xcc, 0xd8, 0x38, 0x91, 0x29, 0xcf,
+	0xa0, 0xc1, 0x4e, 0x2b, 0x5c, 0x51, 0x96, 0xe6, 0x19, 0xf1, 0xdd, 0x3b, 0x61, 0x29, 0x59, 0x28,
+	0x0d, 0xa8, 0x69, 0x8b, 0x25, 0xbd, 0x7b, 0xf9, 0x1a, 0xba, 0xc5, 0xd0, 0x51, 0x13, 0xf6, 0xfe,
+	0x64, 0xea, 0x86, 0x54, 0x42, 0x2d, 0xa8, 0x8d, 0x34, 0xf5, 0x42, 0x93, 0xca, 0x08, 0xa0, 0xce,
+	0xc0, 0x8b, 0xb7, 0x52, 0xe5, 0xcd, 0xbf, 0x00, 0x6a, 0xef, 0xdf, 0xdb, 0xde, 0x02, 0xbd, 0x82,
+	0x86, 0xa8, 0x2a, 0xb4, 0x2f, 0xf2, 0xc0, 0xad, 0x1e, 0x3f, 0x16, 0xab, 0x42, 0xcd, 0x29, 0x25,
+	0xf4, 0x1a, 0xda, 0x36, 0xa1, 0x59, 0x09, 0x1c, 0x08, 0xb5, 0x14, 0x38, 0xde, 0x04, 0x94, 0x12,
+	0x7a, 0x0e, 0xf5, 0x21, 0xa1, 0xec, 0x79, 0x5d, 0x74, 0x91, 0x0d, 0x2a, 0x9f, 0x2a, 0x25, 0xf4,
+	0x3d, 0x80, 0x15, 0xde, 0x92, 0x28, 0x0c, 0xb6, 0x35, 0x53, 0xa3, 0x69, 0xfd, 0x28, 0x25, 0x74,
+	0x0a, 0x6d, 0xfb, 0x7a, 0x45, 0x67, 0xe1, 0xed, 0xc3, 0xf4, 0x7f, 0x07, 0x2d, 0x4c, 0x2e, 0xc3,
+	0x90, 0x3e, 0x48, 0x9b, 0xe5, 0x94, 0x86, 0xcb, 0x39, 0xb6, 0xfa, 0x6c, 0x30, 0x92, 0xe8, 0x7f,
+	0x53, 0xde, 0xc0, 0x81, 0x4d, 0xdd, 0x88, 0x7e, 0x0d, 0xe7, 0x47, 0x38, 0xc4, 0x24, 0xde, 0x60,
+	0xa5, 0x13, 0x59, 0x1c, 0xff, 0x2e, 0xde, 0x8b, 0x24, 0xa3, 0xc6, 0x04, 0x6d, 0x57, 0xfb, 0x71,
+	0x6e, 0xfe, 0x2b, 0x25, 0xf4, 0x5b, 0xf6, 0x46, 0xa2, 0xfc, 0x9d, 0x50, 0x0c, 0xa7, 0xbd, 0x56,
+	0x8b, 0x93, 0x7c, 0x0e, 0x09, 0xcd, 0x5e, 0x09, 0xbb, 0x43, 0x4f, 0xc5, 0x3c, 0xf4, 0x2e, 0xb3,
+	0x1b, 0xac, 0x32, 0xca, 0x8e, 0x50, 0x76, 0xf0, 0xde, 0xe6, 0xce, 0x6d, 0x77, 0xfc, 0xf7, 0xe4,
+	0x56, 0x90, 0x54, 0xdf, 0xdf, 0xb1, 0x99, 0x1d, 0x9c, 0x9f, 0xe0, 0x30, 0xe7, 0x28, 0x36, 0x03,
+	0xcb, 0x34, 0x32, 0x77, 0xeb, 0x97, 0xca, 0x6e, 0x77, 0x59, 0x29, 0x3e, 0x38, 0xc4, 0xd7, 0xd0,
+	0x15, 0x9c, 0x07, 0x47, 0xf8, 0x0e, 0xa4, 0xb5, 0x9b, 0xaf, 0x0a, 0xf0, 0xf7, 0xb0, 0x2f, 0xea,
+	0x26, 0x79, 0x44, 0x3f, 0x2c, 0xc4, 0xb7, 0xd0, 0x16, 0x2c, 0xfe, 0xb6, 0x7e, 0x18, 0xe9, 0x3d,
+	0x3c, 0xb1, 0xf9, 0x39, 0xf3, 0x69, 0xa7, 0x07, 0x33, 0x6f, 0xea, 0xb2, 0x4e, 0x83, 0x8e, 0xd6,
+	0xf4, 0xfc, 0x20, 0xfc, 0x19, 0x1b, 0x3e, 0xbd, 0xd7, 0x46, 0x71, 0x98, 0xee, 0xb2, 0xf1, 0x3d,
+	0x34, 0x87, 0x84, 0x26, 0xfd, 0x75, 0x47, 0xe4, 0x69, 0xb2, 0xb9, 0x02, 0xcf, 0xed, 0x41, 0xff,
+	0xda, 0x0d, 0xe6, 0x84, 0x8d, 0x8a, 0xe4, 0xbd, 0x8e, 0x84, 0x4a, 0x6e, 0x78, 0xec, 0x72, 0xf4,
+	0x11, 0xbe, 0x49, 0x0a, 0x7b, 0xfb, 0xed, 0xbe, 0xc3, 0xef, 0xb7, 0x6b, 0x68, 0x4b, 0x5f, 0x29,
+	0x5d, 0xd6, 0xf9, 0x1f, 0x1a, 0x6f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x62, 0x43, 0x1a, 0x58,
+	0x2f, 0x11, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
diff --git a/api/bbsim/bbsim.proto b/api/bbsim/bbsim.proto
index dab179d..cf511b3 100644
--- a/api/bbsim/bbsim.proto
+++ b/api/bbsim/bbsim.proto
@@ -48,6 +48,10 @@
     string HwAddress = 8;
     int32 PortNo = 9;
     repeated Service services = 10;
+    int32 ImageSoftwareExpectedSections = 11;
+    int32 ImageSoftwareReceivedSections = 12;
+    int32 ActiveImageEntityId = 13;
+    int32 CommittedImageEntityId = 14;
 }
 
 message Service {
diff --git a/cmd/bbsim/bbsim.go b/cmd/bbsim/bbsim.go
index 52cdd0c..d7a85b9 100644
--- a/cmd/bbsim/bbsim.go
+++ b/cmd/bbsim/bbsim.go
@@ -18,6 +18,7 @@
 
 import (
 	"context"
+	"github.com/opencord/bbsim/internal/bbsim/responders/webserver"
 	"net"
 	"net/http"
 	"os"
@@ -33,7 +34,6 @@
 	"github.com/opencord/bbsim/internal/bbsim/api"
 	"github.com/opencord/bbsim/internal/bbsim/devices"
 	"github.com/opencord/bbsim/internal/bbsim/dmiserver"
-	"github.com/opencord/bbsim/internal/bbsim/responders/sadis"
 	"github.com/opencord/bbsim/internal/common"
 	log "github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
@@ -188,7 +188,7 @@
 	log.Debugf("Started APIService")
 	if common.Config.BBSim.SadisServer {
 		wg.Add(1)
-		go sadis.StartRestServer(olt, &wg)
+		go webserver.StartRestServer(olt, &wg)
 	}
 
 	dms, dmserr := dmiserver.StartDmiAPIServer()
diff --git a/configs/software-image-small.img b/configs/software-image-small.img
new file mode 100644
index 0000000..0c8ca08
--- /dev/null
+++ b/configs/software-image-small.img
@@ -0,0 +1,4 @@
+# This is a file to mimic an image software download via OMCI.
+# BBSim doesn't care about the size of the file, but we need to know the source so we can compare.
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam a scelerisque nibh. Donec vitae imperdiet nulla, non hendrerit est. Pellentesque turpis leo, aliquam a libero vitae, malesuada eleifend velit. Quisque non ornare neque. Maecenas vulputate justo vitae vehicula porta. Proin pellentesque lacus non neque bibendum vehicula. Vestibulum sollicitudin, nisl quis semper hendrerit, dolor lacus dapibus dolor, ut volutpat enim augue at magna. Vestibulum neque urna, sagittis eget dui vel, pulvinar varius magna. Vestibulum condimentum iaculis urna ac congue. Proin fringilla id felis pellentesque rutrum. Phasellus eu sodales eros. Nullam laoreet blandit lacus. Nulla pellentesque euismod dolor tempus congue. Donec vel dui varius, maximus enim eget, molestie orci.
\ No newline at end of file
diff --git a/configs/software-image.img b/configs/software-image.img
new file mode 100644
index 0000000..7880fd7
--- /dev/null
+++ b/configs/software-image.img
@@ -0,0 +1,102 @@
+# This is a file to mimic an image software download via OMCI.
+# BBSim doesn't care about the size of the file, but we need to know the source so we can compare.
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam a scelerisque nibh. Donec vitae imperdiet nulla, non hendrerit est. Pellentesque turpis leo, aliquam a libero vitae, malesuada eleifend velit. Quisque non ornare neque. Maecenas vulputate justo vitae vehicula porta. Proin pellentesque lacus non neque bibendum vehicula. Vestibulum sollicitudin, nisl quis semper hendrerit, dolor lacus dapibus dolor, ut volutpat enim augue at magna. Vestibulum neque urna, sagittis eget dui vel, pulvinar varius magna. Vestibulum condimentum iaculis urna ac congue. Proin fringilla id felis pellentesque rutrum. Phasellus eu sodales eros. Nullam laoreet blandit lacus. Nulla pellentesque euismod dolor tempus congue. Donec vel dui varius, maximus enim eget, molestie orci.
+
+Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam in dui nec magna malesuada aliquam eget vel mi. Aliquam mauris turpis, tempor nec vestibulum in, ultrices scelerisque ex. Fusce fermentum, est id pulvinar suscipit, felis mauris euismod ligula, eu pretium lectus justo non tortor. Sed in fermentum leo. Aenean eget posuere libero, iaculis congue erat. Praesent vel neque a augue tempus sodales. Nam ornare convallis justo a commodo. Proin aliquet tempus ex eu mattis. Maecenas a purus a metus posuere auctor. Curabitur porta massa purus, ut facilisis ante efficitur sit amet. Cras nisl dolor, tincidunt vel semper quis, pellentesque et ipsum.
+
+Aliquam erat volutpat. Proin tincidunt, dolor eget convallis porta, tortor ante gravida lectus, non pellentesque odio ipsum quis turpis. Maecenas auctor dapibus purus, sed vehicula nisi blandit ut. Duis sodales dui et neque bibendum condimentum. Phasellus in ultrices tortor, non blandit leo. Aliquam sollicitudin eros augue, auctor tincidunt enim finibus et. Vestibulum fringilla eros sit amet libero luctus hendrerit. Quisque aliquet sodales sapien, ut egestas diam scelerisque sed. Donec commodo fermentum venenatis. Pellentesque laoreet sapien non condimentum mollis. Aenean aliquam tincidunt metus, sit amet aliquam massa ornare vitae.
+
+Vivamus lacinia vel augue a imperdiet. Vestibulum feugiat lobortis accumsan. Vestibulum elit lorem, tincidunt sit amet purus eget, dictum scelerisque arcu. Praesent ultrices mi erat, eu euismod nulla venenatis et. Nulla ultricies feugiat lacus id efficitur. Nulla dapibus nisl ipsum, nec ornare lorem mollis id. Proin ut pharetra ligula, vitae ultricies nunc. Pellentesque tincidunt porta felis et ultricies. Maecenas dictum condimentum luctus. Donec condimentum fermentum eros at rhoncus. Aliquam et pharetra erat. Suspendisse vitae sapien porttitor dui porta accumsan. Etiam pellentesque magna arcu, et sodales lacus porttitor ut.
+
+Phasellus et auctor lorem, semper porta neque. Duis mollis dictum lorem quis consectetur. Aliquam vel ante pellentesque urna scelerisque aliquam sed eu mauris. Nulla ullamcorper, massa at viverra ullamcorper, elit lacus pulvinar odio, ut eleifend leo nisl nec elit. Quisque volutpat elit faucibus lectus ornare dignissim. Sed rhoncus, felis vel maximus aliquam, tortor mi egestas magna, et commodo enim erat eu diam. Maecenas at nulla in nisl consectetur tristique dapibus et lorem.
+
+Nam felis ex, finibus sollicitudin tincidunt et, commodo id nisl. Sed et bibendum erat. Vestibulum gravida non lorem id ultricies. Nullam tincidunt velit quis consectetur porta. Nunc nec semper ex. Sed posuere bibendum consectetur. Quisque eu ultricies felis. Vestibulum facilisis condimentum odio, sed vulputate sapien. Ut quam felis, imperdiet id imperdiet eget, pellentesque eget quam. Vivamus et tortor non urna sodales volutpat et ultrices nulla. Suspendisse tellus turpis, sagittis non purus id, fringilla condimentum lorem. Vivamus id lectus non lacus consectetur ornare in ut tortor. Sed molestie gravida magna eu ornare. Donec eget pulvinar tortor, in dapibus sapien. Donec eu faucibus eros. Phasellus at cursus enim.
+
+Nam sed blandit ante. Integer at mauris vel eros pulvinar pretium at vitae lorem. Ut vel turpis nisl. Aliquam urna libero, aliquet eu gravida sit amet, tincidunt ac ipsum. Donec nec purus magna. Duis sodales tortor lectus, sed pharetra felis condimentum nec. Nulla suscipit eros urna, eu rhoncus justo volutpat sit amet. Nunc nunc sem, varius vitae ultricies sit amet, pretium non turpis. Cras egestas dui a ipsum imperdiet sollicitudin. Integer non tempor ex, non ultrices urna. Quisque ipsum arcu, euismod pretium suscipit eu, cursus sed arcu. Proin tempus interdum neque, vel fermentum felis hendrerit eget.
+
+Donec a sollicitudin tortor, in fermentum ipsum. Mauris ut ex ante. Phasellus velit mauris, congue sed cursus vel, vestibulum a diam. Praesent laoreet eu velit eu tempor. Proin nec aliquet enim, tincidunt mattis arcu. In sit amet pellentesque ligula. Quisque ligula lorem, interdum nec facilisis ut, maximus et lectus. Proin tempor purus sit amet tristique interdum. Nam ultricies metus nec ultrices bibendum. Quisque fringilla metus eu quam accumsan, interdum ornare lacus feugiat.
+
+Suspendisse ut dapibus ligula, quis hendrerit ipsum. Quisque vitae tellus cursus, tempor mauris non, condimentum ex. In id nulla a metus pellentesque mollis. Vestibulum condimentum non massa eu egestas. Pellentesque facilisis quam eu eleifend sodales. Integer placerat laoreet magna quis ullamcorper. Duis varius facilisis velit, non volutpat ipsum. Morbi tempor tincidunt mattis. Phasellus eget mi a ante efficitur cursus ut vel augue.
+
+Fusce quis posuere lacus. Nunc lacinia porttitor turpis. Aenean ligula leo, condimentum sed massa vel, aliquam rutrum velit. In consequat vestibulum nisl, sit amet tincidunt elit posuere eu. Sed non fermentum lectus. Aenean fermentum metus at nisl aliquam faucibus. Duis cursus sapien arcu, eget ultricies dolor euismod id. Aenean ut leo sit amet arcu sollicitudin aliquet. Quisque lorem ligula, placerat vitae finibus vel, rhoncus et mauris. Integer congue mattis nunc eget tristique. Phasellus nec luctus ipsum, aliquam tempus nisi.
+
+Morbi aliquet eros diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lobortis nunc id dapibus vulputate. Integer efficitur congue erat, ut venenatis odio scelerisque id. Mauris tempus, risus et pretium mollis, augue nibh aliquam lacus, nec rutrum orci dolor eu metus. Duis ipsum purus, dictum eu dolor at, hendrerit fringilla justo. Quisque eget gravida lorem. Sed maximus sodales tempus. Quisque rutrum velit et ex consequat ultrices. Donec sed maximus urna. Vivamus lectus erat, commodo sed tincidunt at, ultricies sed odio. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut facilisis nunc. Sed eget est nisl. Aenean gravida purus et euismod mollis. In tristique aliquet justo, vel lacinia mi molestie non.
+
+In blandit nec felis at congue. Phasellus commodo enim eu arcu vulputate pharetra. Phasellus orci metus, consectetur at lorem in, luctus accumsan enim. Curabitur ac tellus lorem. Ut et posuere nisi, ut sagittis lorem. Morbi ornare lacus eu ultricies tincidunt. Curabitur semper magna id orci fringilla eleifend. Mauris ut odio porta, blandit purus eget, luctus tortor. In hac habitasse platea dictumst. Mauris ut pharetra mi, nec dignissim mi. Curabitur faucibus imperdiet ex at hendrerit. Maecenas vestibulum libero venenatis, dapibus lectus non, efficitur enim. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur hendrerit, eros in egestas pretium, nunc lorem tempus nulla, in interdum ante neque a lorem.
+
+Donec sollicitudin arcu vitae facilisis vestibulum. Suspendisse sollicitudin, magna vel aliquam maximus, dolor nunc varius sem, quis aliquam urna sapien quis justo. Mauris metus nunc, aliquam iaculis accumsan ac, ullamcorper non mi. Nulla facilisi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas dictum pulvinar augue sed efficitur. Pellentesque sodales, orci sed pulvinar ullamcorper, quam risus ullamcorper lorem, vel porttitor sapien mi ut turpis. Cras a quam suscipit, feugiat arcu quis, congue massa. Etiam vel ultricies nunc. Donec non luctus elit. Quisque vel aliquet arcu, luctus malesuada nisi. In aliquam lectus in mollis efficitur.
+
+Morbi vitae nulla at est commodo volutpat. Nunc vitae eros nec sapien convallis finibus. Pellentesque nisi nisl, hendrerit nec consectetur egestas, vehicula et magna. Fusce sed imperdiet nulla. Nunc molestie erat sed ligula iaculis venenatis ac nec nibh. Vivamus cursus tellus a sem volutpat, eu vehicula lacus porttitor. Sed eu nunc a leo fringilla tincidunt sit amet et leo. Suspendisse quis erat leo. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ultricies odio ut tellus rhoncus egestas. Phasellus interdum, dolor vitae posuere pulvinar, nunc ipsum aliquet eros, eget consectetur purus risus eu elit. Integer interdum, ipsum quis tempus dignissim, nisi ante aliquet ante, nec pretium justo massa eu lectus. Suspendisse potenti. Etiam tempor sagittis nibh. Cras aliquam mi non erat efficitur, id fringilla magna laoreet. Maecenas malesuada commodo est vitae eleifend.
+
+Nulla eget augue ultrices, luctus velit eu, interdum diam. Vestibulum congue non ante sed volutpat. Vivamus vestibulum ex nunc, et commodo mi consectetur ac. Aliquam pulvinar sapien quis risus dictum consectetur. Duis quis pretium nunc. Donec egestas interdum vulputate. Praesent est orci, ullamcorper sit amet tempus sit amet, tempor id augue. Curabitur cursus risus quis aliquam cursus. Morbi magna lorem, tempus id placerat eget, porttitor in velit. Praesent ullamcorper venenatis neque, ac tristique quam. Fusce lacinia ante odio, quis cursus risus sollicitudin sit amet. Vestibulum eros felis, viverra rutrum efficitur et, accumsan id mi. Aenean ut libero non sem fringilla congue cursus malesuada elit.
+
+Proin id diam sollicitudin, sollicitudin libero a, sollicitudin odio. Suspendisse pharetra luctus neque, nec mollis sem consectetur et. Donec et lacus sagittis, feugiat mauris vel, mattis est. Donec euismod sit amet nunc non viverra. Quisque ut metus nec magna laoreet congue ut vel purus. Fusce euismod nisi vel lorem convallis, et iaculis dui luctus. Nam et egestas ipsum. Donec eleifend urna eget odio dapibus tincidunt. Duis faucibus sollicitudin risus, id ultrices metus fringilla vitae. Sed malesuada metus non nulla iaculis, non hendrerit elit luctus. Mauris ac porttitor nunc.
+
+Ut id lectus scelerisque, euismod velit eu, posuere justo. Morbi tempus porta risus, at pulvinar orci dapibus ac. Quisque risus lacus, congue quis pharetra sed, gravida id nisi. Maecenas nisl felis, rutrum non elementum in, fermentum vitae neque. Proin id imperdiet sem. Phasellus risus lacus, maximus at efficitur vel, pellentesque mattis magna. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris dignissim non elit vel ullamcorper. Vestibulum vitae auctor erat. Nunc id elementum ante. Maecenas ut ligula ut dui mollis dapibus et sed nulla. Pellentesque vitae sagittis lectus. Donec vehicula egestas dui id semper. Vivamus ac tempus dui. Sed interdum metus vitae bibendum gravida.
+
+Aliquam eleifend, risus vitae placerat congue, dui tellus efficitur nunc, vitae sagittis mauris purus vel augue. Vivamus sit amet ullamcorper risus. Nam pulvinar, mauris eget varius placerat, lacus enim mollis risus, ut sagittis metus justo in ex. Aliquam sagittis placerat ipsum, ut tempor urna mollis a. In euismod cursus iaculis. Fusce ligula risus, pulvinar ut orci at, scelerisque bibendum lacus. Fusce at elementum nunc, in pellentesque felis. Maecenas sit amet magna risus. Pellentesque in odio eu mi egestas scelerisque non sed orci. Fusce eros ante, euismod ac interdum vitae, cursus ac diam. Ut quis congue nisi.
+
+Proin vitae risus at lectus cursus varius a eu lectus. Praesent vestibulum fermentum metus eu dignissim. Maecenas vel iaculis odio, quis ultrices libero. Aenean ante odio, scelerisque id euismod vel, mollis id neque. Pellentesque auctor sed enim ac consequat. Suspendisse in purus non nibh tincidunt vehicula. Suspendisse potenti. Integer vel enim vel lorem molestie lacinia at et enim. Pellentesque vel lacus pulvinar, convallis velit quis, luctus lectus. Mauris aliquet, nunc sed auctor facilisis, quam nibh maximus tellus, finibus condimentum orci elit non ante. Morbi in accumsan ex. Vivamus iaculis elit sit amet ultrices dictum. Etiam consectetur mauris quis leo dignissim ullamcorper vitae et metus. Nullam et metus convallis, bibendum leo vel, congue velit.
+
+Donec mi nunc, euismod eget ullamcorper vel, feugiat at eros. Cras sem dui, ullamcorper vitae viverra ut, lobortis sit amet turpis. Nunc commodo, ex nec vehicula faucibus, mauris purus aliquet leo, accumsan tristique velit urna rutrum purus. Vestibulum quis imperdiet purus. Etiam quis eros sit amet arcu volutpat molestie. Nunc ante enim, pulvinar a tristique et, laoreet vel metus. Duis sed sem arcu. Sed feugiat sagittis porta.
+
+Nam non nulla a ex tempor sagittis et quis lectus. Sed a mattis ex. Curabitur ex turpis, varius eu lorem ac, malesuada ornare augue. Phasellus id aliquam justo. Vivamus bibendum porttitor porta. Nulla viverra tempus nulla, nec varius arcu consectetur et. Etiam fringilla nisl vel dolor accumsan pellentesque. Vestibulum eu lectus sit amet nisi luctus fringilla ut varius urna.
+
+Duis vitae diam id quam pulvinar viverra. Cras accumsan quam augue. Donec scelerisque luctus mi in maximus. Phasellus pulvinar orci quis lorem ultrices iaculis. Suspendisse potenti. Maecenas tristique massa vel dolor posuere, in sollicitudin felis tincidunt. Etiam molestie placerat consequat. Morbi et odio eget nisi cursus accumsan eget sed ligula. Integer dignissim et magna gravida commodo. Morbi euismod auctor lobortis.
+
+Praesent sed vestibulum quam. Fusce egestas cursus fringilla. Sed imperdiet sit amet leo nec fermentum. Phasellus bibendum ac lectus quis auctor. Nulla condimentum purus at diam aliquam, ut finibus arcu egestas. Fusce rhoncus orci eu mauris interdum, quis vehicula enim euismod. Sed quis tincidunt justo, et tincidunt quam. Proin bibendum, purus ac rutrum ultrices, leo neque condimentum ligula, sodales dignissim justo ex ac odio. Nunc eu felis rhoncus, molestie ante et, mollis velit. Quisque accumsan ex sed rhoncus placerat. Quisque dolor mauris, eleifend et lectus eu, viverra lobortis nulla. In sed est eget tellus consectetur malesuada sit amet vel nisl.
+
+Curabitur eget hendrerit est. Mauris tincidunt lectus id ante aliquet, a aliquam erat aliquet. Pellentesque viverra arcu quis molestie condimentum. Aenean accumsan commodo nisl. Quisque malesuada nisl lacus, eu bibendum mauris vehicula at. Donec molestie faucibus erat vitae feugiat. In venenatis dolor hendrerit semper blandit. Maecenas sit amet rutrum ante. Praesent pellentesque vehicula vehicula. Cras et dictum quam. Nulla imperdiet congue tincidunt. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
+
+Morbi eleifend enim sodales, condimentum felis non, congue lectus. Aliquam erat volutpat. Ut ut blandit erat, vel gravida ante. Etiam nec mollis mauris. Suspendisse potenti. Integer interdum lectus ac interdum hendrerit. Duis ornare odio diam, sed sollicitudin augue lobortis vitae. In turpis tortor, maximus quis hendrerit eget, maximus eu velit. Quisque suscipit tortor id velit feugiat lobortis. Nunc pretium consequat libero, vel semper ante porttitor eget. Aliquam eros sapien, pharetra id lacus eget, mollis interdum ante. Etiam venenatis egestas enim nec egestas. Curabitur nec nisi vitae odio faucibus tempor non a orci. Sed varius ante imperdiet, luctus nunc vitae, hendrerit justo. Nunc sed tincidunt ex. Suspendisse enim sem, porta non suscipit sed, consequat id nulla.
+
+Nulla tincidunt et nulla non fringilla. Aliquam id maximus quam, id lacinia libero. Praesent ante libero, ultricies ut dolor ut, egestas placerat justo. Nam ullamcorper nisi et ultrices posuere. Nunc cursus nec risus eu rhoncus. Pellentesque cursus feugiat erat quis sollicitudin. Sed eleifend, risus eu mollis egestas, mi enim iaculis sem, sed viverra mauris nunc a lacus. Donec ultrices urna leo, vel egestas augue fringilla a. Vestibulum molestie sollicitudin est id sagittis. Vivamus mattis pharetra ipsum, ut elementum risus laoreet ut. In eget laoreet justo. Sed at suscipit ligula. Fusce a varius erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus fermentum blandit tortor, sit amet dignissim urna aliquam sed. Vivamus vel iaculis velit, at tincidunt odio.
+
+Pellentesque pretium dictum eros id eleifend. Donec sit amet volutpat lacus, commodo mattis leo. Aliquam nec cursus leo. Donec ornare augue in neque tincidunt pharetra. Sed id massa nec orci porttitor efficitur sit amet ac mi. Nullam non porttitor velit. Etiam blandit congue magna id bibendum. Aenean aliquam ac magna nec rhoncus. In nec augue ac quam posuere varius. Aliquam lacinia eget neque non condimentum. Etiam sit amet ornare sem. Sed pulvinar justo ac libero mollis, lacinia ultricies leo gravida. Nullam porttitor tempus hendrerit. Integer eget fermentum risus. Praesent in placerat mauris. Vivamus auctor lacinia molestie.
+
+Quisque eu ex mauris. Nam mattis in nunc non bibendum. Curabitur ante magna, vestibulum et massa eget, eleifend laoreet libero. Pellentesque dignissim imperdiet turpis at gravida. Aliquam ornare metus in leo tincidunt, non facilisis magna hendrerit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec volutpat risus magna, nec porttitor lectus blandit a. Ut cursus magna convallis odio volutpat, et convallis velit ultricies. Donec eu venenatis diam, in fermentum arcu. Praesent tempus risus et velit ornare dignissim ut nec eros. Sed mattis lacus sed ex hendrerit egestas.
+
+Integer commodo euismod suscipit. Fusce interdum velit dictum mi suscipit iaculis. Suspendisse arcu est, fringilla quis metus ut, facilisis dictum leo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Curabitur mi nunc, euismod vel diam eget, commodo ornare felis. Aliquam tincidunt, augue ut mattis gravida, ipsum odio vestibulum metus, quis faucibus dui ipsum ac elit. Curabitur sit amet viverra felis. Praesent id orci ultricies, dictum nulla nec, fermentum justo. Morbi commodo, lectus non scelerisque volutpat, arcu dolor consequat diam, et imperdiet est erat vitae diam. Vivamus eget mauris ut tortor rutrum luctus. Fusce nunc nisi, ornare non varius quis, blandit nec nulla. Pellentesque blandit ornare commodo.
+
+Cras vitae ultricies augue. Aliquam volutpat, tortor sit amet accumsan tempus, ante nisi ornare enim, sed pharetra odio erat vitae purus. Mauris diam odio, pulvinar ac faucibus vel, luctus eu sapien. Nunc aliquam feugiat convallis. In hac habitasse platea dictumst. Donec scelerisque gravida lectus in feugiat. Sed vitae interdum augue. Nam vel vehicula lacus. Donec mi sem, rutrum auctor pharetra in, sagittis vitae nisi. Cras faucibus pellentesque nibh vitae semper.
+
+Nam vel aliquet ipsum. Suspendisse mollis lorem est, eu efficitur odio dictum sit amet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce varius elementum odio, at egestas enim ornare sed. Etiam sed felis mi. Fusce semper quam id justo volutpat rhoncus. Nullam ultrices facilisis mi. Vivamus ac condimentum ex, ac congue ante. Suspendisse pulvinar nisl ac massa semper, at aliquet magna cursus.
+
+Donec efficitur nisi augue, sed iaculis lorem tempus in. Aliquam maximus eu eros ut bibendum. Morbi non libero ligula. In pretium mi sit amet augue tincidunt lacinia. Aenean rhoncus lobortis eros at ultricies. Pellentesque nisi nibh, rhoncus ac quam in, vulputate consectetur justo. Nunc mattis tellus at eros porta posuere. Maecenas vulputate, leo vel ornare dictum, ligula augue facilisis magna, sit amet mattis ante arcu non velit. In elementum ex sed suscipit mollis. Nulla facilisi. Sed arcu sem, mollis eget justo in, elementum eleifend orci.
+
+Ut bibendum, dui ac imperdiet suscipit, tellus felis tincidunt urna, ut aliquet enim libero in leo. Duis vel egestas diam, nec dictum erat. Sed lorem felis, placerat id blandit in, hendrerit in erat. Vivamus luctus lacus arcu, vel gravida odio maximus eget. Sed eleifend nisi eu arcu mollis, at sollicitudin quam interdum. Nunc porttitor sapien est, ac fermentum mi blandit quis. Integer nec mauris at diam feugiat dignissim. Fusce sit amet dolor tincidunt, sollicitudin dolor hendrerit, lacinia nunc. Quisque faucibus, elit at blandit elementum, ligula eros efficitur eros, at placerat ipsum tellus non purus. Duis non magna augue. Vivamus ultrices ultricies mattis. Sed eu urna et leo egestas dictum. Donec sed nisi et ex efficitur imperdiet ut at nisi. Vivamus massa tortor, molestie eget eros in, auctor dictum quam. Praesent at porttitor felis. Donec et massa quis eros rutrum iaculis vitae porttitor tellus.
+
+Fusce sed lectus at justo lobortis hendrerit. Nulla lectus sem, rhoncus in nisi non, dictum vestibulum purus. Nam eu lacus et arcu bibendum fringilla sit amet at arcu. Sed lobortis nisl ut egestas viverra. Aliquam a luctus risus. Morbi sed nisi laoreet, convallis purus in, interdum metus. Donec ex dolor, vulputate in commodo quis, fringilla vel purus. Nullam dolor diam, mattis sed eros ut, facilisis lobortis purus. Proin eu neque quis tortor feugiat semper. Cras vulputate turpis vel mauris dictum faucibus sodales vel lectus. Aliquam quis tortor non ante dictum tincidunt. Fusce eu dolor nisi. Nam a erat ut est viverra pharetra et et metus. Donec scelerisque nunc convallis, faucibus enim quis, venenatis lacus. Maecenas lectus massa, imperdiet aliquet orci eu, viverra tristique dolor.
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus venenatis egestas fringilla. Vivamus congue sapien eget enim venenatis, id iaculis nisi dignissim. Etiam dolor sapien, facilisis nec elit quis, consectetur facilisis velit. Cras porta eu sem quis porta. Proin porta purus molestie porta dictum. Duis non hendrerit sem, maximus porta dolor. In sit amet dui pellentesque mauris ultricies bibendum sed quis tellus. Nullam eget maximus ante. Cras auctor lorem justo, in varius velit finibus at. Vestibulum tempor aliquam iaculis. Nullam laoreet sed enim ut ultrices. Curabitur nec porta dolor. Aenean lectus sapien, faucibus quis dignissim in, convallis ac leo. Nulla eget felis vel neque condimentum pulvinar in sed mauris. Nunc fermentum iaculis justo, ut rutrum nulla imperdiet at.
+
+Suspendisse ut sollicitudin felis. Donec varius rhoncus augue. Morbi nunc augue, pretium ut lobortis vitae, lobortis a libero. Cras sed nibh semper, cursus arcu viverra, ultrices diam. Ut sit amet neque malesuada, sollicitudin justo vitae, molestie ex. Fusce ut velit nisi. Duis id accumsan velit. Praesent luctus diam mauris, id eleifend justo malesuada mollis.
+
+In hac habitasse platea dictumst. Ut quis metus sit amet leo tristique luctus. Fusce fermentum gravida neque quis faucibus. Sed non leo convallis, lobortis velit at, posuere arcu. Pellentesque nec lectus eu odio sollicitudin egestas non eget quam. Sed ac neque nisl. Nullam imperdiet eros dui, consectetur varius magna eleifend vitae. Donec tincidunt purus nec auctor pretium. Ut vel faucibus tellus. Nulla facilisi.
+
+Nulla est orci, placerat ac rutrum a, hendrerit sed mauris. Proin vel iaculis sem. Curabitur diam quam, mollis ac fermentum eu, tincidunt convallis metus. Morbi tempor lacus neque, non fermentum lorem viverra ac. Fusce malesuada tristique mattis. Etiam suscipit mollis iaculis. Aenean leo justo, consectetur ac semper a, egestas sit amet ligula. Mauris non velit ex. Suspendisse eu semper sapien. Nullam faucibus ipsum id tortor vulputate, ac euismod eros sodales. Vivamus mollis maximus tincidunt. Nam libero diam, convallis vel justo varius, sagittis tempus arcu.
+
+Sed iaculis tempus mauris sed pharetra. Fusce commodo sapien eu ex blandit, sit amet eleifend odio dictum. In lectus ligula, mollis at hendrerit sed, venenatis vitae risus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus posuere ultrices ligula et aliquam. In hac habitasse platea dictumst. Nullam laoreet enim hendrerit posuere sollicitudin. In nibh arcu, mollis in gravida id, sagittis quis dui. Sed ullamcorper dui in velit eleifend, eget lacinia purus faucibus. Aliquam varius id est non sollicitudin. Sed ullamcorper fringilla tellus ut tincidunt. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam ipsum elit, congue nec consectetur eu, vestibulum nec quam. Curabitur nec hendrerit mauris. Praesent congue, ipsum in porta malesuada, felis tortor ultrices lacus, et malesuada augue ex ut justo.
+
+Nam fringilla ligula non lorem ultrices imperdiet. Curabitur et consectetur arcu, sit amet luctus tortor. Maecenas ac lacinia mi. Ut consectetur laoreet arcu, posuere laoreet diam sagittis id. Nunc nisi purus, lobortis id euismod id, consectetur id velit. Donec eleifend convallis nibh, volutpat condimentum turpis pulvinar id. Ut ornare, mauris et varius lobortis, ipsum est luctus nisl, venenatis faucibus lectus nisi et libero. Maecenas et nunc tortor. Suspendisse placerat eros et nulla accumsan efficitur. Duis non congue eros. Vestibulum tempor, est sit amet fringilla aliquet, metus diam sodales libero, quis lacinia odio metus et ex. Ut tempus fermentum sem eu tincidunt. Duis vitae cursus nisl. Suspendisse potenti. Curabitur tempor magna nisi, vel ultrices diam bibendum vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
+
+Aliquam convallis urna tellus, ac consectetur ligula porttitor quis. Vivamus nec libero metus. Nulla blandit neque quis felis ornare convallis. Vestibulum in dolor condimentum, rhoncus dolor eget, sollicitudin neque. Nullam sagittis mattis venenatis. Sed mollis iaculis dui in molestie. Praesent euismod varius hendrerit. Mauris ornare est ac hendrerit venenatis. Ut id efficitur tortor, eget consequat urna. Nunc porta mattis arcu, a porttitor neque sagittis et. Nunc porta hendrerit lacus sit amet interdum. Integer suscipit lobortis sem, at fermentum felis consequat eget. Cras aliquam, lorem eget condimentum lobortis, diam elit ultrices quam, vitae porta urna odio in nunc. Vestibulum cursus justo sed magna malesuada, ac placerat odio rhoncus.
+
+Nullam placerat diam nec eros dapibus pulvinar. Donec quis vestibulum quam. Aliquam commodo fringilla urna, non volutpat eros porttitor ac. Etiam nunc odio, lacinia in justo eget, ornare blandit erat. Morbi et dui sed lectus viverra vehicula non rhoncus mauris. Ut arcu nisl, fermentum a dignissim ut, suscipit a risus. Cras odio nibh, eleifend eget pulvinar rhoncus, commodo ut dolor. Sed turpis felis, porta sed tortor vel, posuere molestie lectus. Phasellus quis enim tristique, eleifend arcu quis, imperdiet odio. Sed vitae posuere lectus, eget imperdiet ipsum.
+
+Cras a semper turpis. Curabitur efficitur nunc id nibh efficitur, ut tempor libero dignissim. Curabitur vehicula diam eu leo mollis, eu posuere ex pulvinar. Nullam tempus, nisl et tristique egestas, ligula neque accumsan libero, sit amet vulputate tellus lorem non sem. Mauris quam erat, varius et dignissim et, eleifend a neque. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi quam nunc, aliquet id placerat id, ultrices et massa. Mauris vel dictum nisl, eu bibendum odio.
+
+Mauris mi arcu, interdum eget arcu in, convallis egestas lectus. Vivamus fringilla semper metus at maximus. In hac habitasse platea dictumst. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec feugiat diam tortor, in interdum mauris placerat ut. Integer id pharetra felis. Donec pulvinar vehicula sagittis. Integer a velit massa. Etiam sodales lectus eu neque porttitor fringilla.
+
+Phasellus pulvinar ex quis ex malesuada, in auctor mi ultricies. Etiam eget feugiat dolor. Ut nec augue ac justo ornare porttitor. Vestibulum ac condimentum erat. Donec non ex luctus augue finibus tempus. Integer varius sagittis ultricies. Nullam scelerisque imperdiet ex, quis sodales nulla sagittis pellentesque. Aliquam erat volutpat.
+
+Pellentesque et aliquam elit, sed euismod magna. Praesent nec arcu nec sapien varius cursus et ac nibh. Quisque sit amet eros sed urna semper mattis ut id dui. Nulla facilisi. Maecenas rhoncus mi non luctus volutpat. Aenean laoreet ante ut lacus pretium blandit. Etiam at velit dignissim sapien tincidunt sodales non sed nisi. Praesent pulvinar enim vel ex eleifend, et dictum justo elementum. Mauris sit amet fringilla mauris, sed efficitur libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque elementum ligula sit amet urna finibus, interdum vulputate odio pulvinar.
+
+Nunc scelerisque tortor ac feugiat sagittis. Suspendisse hendrerit orci ac laoreet consectetur. Sed aliquet, leo in iaculis feugiat, dolor nunc ullamcorper mi, vitae vehicula risus purus in arcu. Maecenas luctus venenatis ante, vitae rhoncus magna rhoncus et. Nulla ac rutrum nunc. Donec auctor gravida sapien, in varius ligula elementum ut. Cras facilisis leo vel felis eleifend ullamcorper id sed eros. Nulla volutpat convallis nisi vitae accumsan. Vestibulum commodo pulvinar felis, sit amet pulvinar odio rhoncus sit amet. Quisque malesuada maximus tortor laoreet auctor. Praesent dapibus nunc id mollis maximus. Proin cursus ligula arcu, eu tincidunt mauris interdum vitae. Duis auctor elit vitae sem varius, sit amet ultricies lorem malesuada. Phasellus fringilla vestibulum sapien sed pharetra. Aliquam malesuada, justo non dapibus congue, nisl tortor commodo tortor, nec bibendum quam ante vehicula leo.
+
+Quisque et lectus quis ex rhoncus porta convallis sit amet ligula. Proin eget magna id justo imperdiet convallis vel vitae ligula. Fusce lobortis dolor in tincidunt euismod. Vivamus dignissim ante imperdiet, fermentum lacus ac, elementum nunc. Aliquam maximus quam eget augue interdum, ut egestas mauris tincidunt. Sed vitae turpis a libero interdum malesuada id a quam. Vestibulum suscipit tellus purus, ut rhoncus libero semper quis. Nulla tincidunt sed ex non tincidunt. Nulla eu mollis massa. Pellentesque auctor, metus nec vulputate tincidunt, dolor mi lobortis felis, id iaculis ex ante ut nunc. In pulvinar, ante at volutpat congue, augue lectus varius elit, sit amet hendrerit dui tortor et leo. Vestibulum sed tincidunt diam, nec molestie nibh.
+
+Donec augue nunc, bibendum non odio vel, egestas iaculis justo. Vestibulum ac vestibulum dui. Nam blandit tempus magna ac finibus. Nullam nec ante vehicula, lacinia sapien at, placerat eros. Curabitur mauris dui, lobortis id tellus eu, commodo mattis dui. Phasellus leo mi, pretium ut sapien ac, imperdiet lacinia ligula. Nullam tempor purus tellus, ac lacinia nibh rhoncus non. Aenean vehicula lectus est.
+
+Aenean mattis velit et nisi hendrerit, ac mollis ligula laoreet. Fusce ornare dolor est, quis varius neque bibendum eu. Aliquam lacinia bibendum varius. Praesent eget vehicula magna, nec pretium nunc. Nullam in bibendum lectus, a efficitur libero. In hac habitasse platea dictumst. Suspendisse potenti. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sed ipsum nibh. Maecenas sed dictum nisi. Nulla dolor dui, elementum at rhoncus vel, vehicula at augue. Praesent pharetra eu lectus ac accumsan.
\ No newline at end of file
diff --git a/go.mod b/go.mod
index bebf708..3b018ed 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@
 	github.com/olekukonko/tablewriter v0.0.4
 	github.com/opencord/cordctl v0.0.0-20190909161711-01e9c1f04bf4
 	github.com/opencord/device-management-interface v0.11.0
-	github.com/opencord/omci-lib-go v0.15.4
+	github.com/opencord/omci-lib-go v0.16.1
 	github.com/opencord/voltha-protos/v4 v4.0.15
 	github.com/pkg/errors v0.8.1 // indirect
 	github.com/sirupsen/logrus v1.4.2
diff --git a/go.sum b/go.sum
index da02099..5718e49 100644
--- a/go.sum
+++ b/go.sum
@@ -87,8 +87,8 @@
 github.com/opencord/cordctl v0.0.0-20190909161711-01e9c1f04bf4/go.mod h1:/+3S0pwQUy7HeKnH0KfKp5W6hmh/LdZzuZTNT/m7vA4=
 github.com/opencord/device-management-interface v0.11.0 h1:hoKjrkQWPr0IFXWn6HbGdV1Bk5v0gijM7P4VjUJvNh8=
 github.com/opencord/device-management-interface v0.11.0/go.mod h1:G1owSqGBGaqllrwtjxfLTsy9EDsGhdhmqkJM3XOnPD0=
-github.com/opencord/omci-lib-go v0.15.4 h1:g+IkuCZeS7Okvm7TxjobaLwX6UHo26hCvdyyqX9Bfi8=
-github.com/opencord/omci-lib-go v0.15.4/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
+github.com/opencord/omci-lib-go v0.16.1 h1:vYCqT3kN1bs2IfQXS3X/I106qY40zJfYimLLTcZ2QWY=
+github.com/opencord/omci-lib-go v0.16.1/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
 github.com/opencord/voltha-protos/v4 v4.0.15 h1:TOKYlt/75w5pxT44HeYfo2kqKvqmHzVpUkiCHOMJTN8=
 github.com/opencord/voltha-protos/v4 v4.0.15/go.mod h1:W/OIFIyvFh/C0vchRUuarIsMylEhzCRM9pNxLvkPtKc=
 github.com/pierrec/lz4 v2.4.1+incompatible h1:mFe7ttWaflA46Mhqh+jUfjp2qTbPYxLB2/OyBppH9dg=
diff --git a/internal/bbsim/api/onus_handler.go b/internal/bbsim/api/onus_handler.go
index 276cddb..8f606d0 100644
--- a/internal/bbsim/api/onus_handler.go
+++ b/internal/bbsim/api/onus_handler.go
@@ -37,13 +37,17 @@
 	for _, pon := range olt.Pons {
 		for _, o := range pon.Onus {
 			onu := bbsim.ONU{
-				ID:            int32(o.ID),
-				SerialNumber:  o.Sn(),
-				OperState:     o.OperState.Current(),
-				InternalState: o.InternalState.Current(),
-				PonPortID:     int32(o.PonPortID),
-				PortNo:        int32(o.PortNo),
-				Services:      convertBBsimServicesToProtoServices(o.Services),
+				ID:                            int32(o.ID),
+				SerialNumber:                  o.Sn(),
+				OperState:                     o.OperState.Current(),
+				InternalState:                 o.InternalState.Current(),
+				PonPortID:                     int32(o.PonPortID),
+				PortNo:                        int32(o.PortNo),
+				Services:                      convertBBsimServicesToProtoServices(o.Services),
+				ImageSoftwareReceivedSections: int32(o.ImageSoftwareReceivedSections),
+				ImageSoftwareExpectedSections: int32(o.ImageSoftwareExpectedSections),
+				ActiveImageEntityId:           int32(o.ActiveImageEntityId),
+				CommittedImageEntityId:        int32(o.CommittedImageEntityId),
 			}
 			onus.Items = append(onus.Items, &onu)
 		}
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index f6a4b40..f9ef936 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -47,6 +47,17 @@
 	"module": "OLT",
 })
 
+const (
+	onuIdStart     = 1
+	onuIdEnd       = 127
+	allocIdStart   = 1024
+	allocIdEnd     = 16383
+	gemportIdStart = 1024
+	gemportIdEnd   = 65535
+	flowIdStart    = 1
+	flowIdEnd      = 65535
+)
+
 type OltDevice struct {
 	sync.Mutex
 	OltServer *grpc.Server
@@ -288,7 +299,7 @@
 			}
 
 			for _, onu := range pon.Onus {
-				_ = onu.InternalState.Event("disable")
+				_ = onu.InternalState.Event(OnuTxDisable)
 			}
 		}
 	} else {
@@ -297,7 +308,7 @@
 			// ONUs are not automatically disabled when a PON goes down
 			// as it's possible that it's an admin down and in that case the ONUs need to keep their state
 			for _, onu := range pon.Onus {
-				_ = onu.InternalState.Event("disable")
+				_ = onu.InternalState.Event(OnuTxDisable)
 			}
 		}
 	}
@@ -821,12 +832,12 @@
 			"OnuId":  _onu.ID,
 		}).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
 	}
-	if err := _onu.InternalState.Event("enable"); err != nil {
+	if err := _onu.InternalState.Event(OnuTxEnable); err != nil {
 		oltLogger.WithFields(log.Fields{
 			"IntfId": _onu.PonPortID,
 			"OnuSn":  _onu.Sn(),
 			"OnuId":  _onu.ID,
-		}).Infof("Failed to transition ONU to enabled state: %s", err.Error())
+		}).Infof("Failed to transition ONU to %s state: %s", OnuStateEnabled, err.Error())
 	}
 
 	// NOTE we need to immediately activate the ONU or the OMCI state machine won't start
@@ -862,12 +873,12 @@
 		}).Error("Can't find Onu")
 	}
 
-	if err := _onu.InternalState.Event("disable"); err != nil {
+	if err := _onu.InternalState.Event(OnuTxDisable); err != nil {
 		oltLogger.WithFields(log.Fields{
 			"IntfId": _onu.PonPortID,
 			"OnuSn":  _onu.Sn(),
 			"OnuId":  _onu.ID,
-		}).Infof("Failed to transition ONU to disabled state: %s", err.Error())
+		}).Infof("Failed to transition ONU to %s state: %s", OnuStateDisabled, err.Error())
 	}
 
 	// ONU Re-Discovery
@@ -1084,14 +1095,23 @@
 
 		// if its ONU flow remove it from ONU also
 		if storedFlow.AccessIntfId != -1 {
-			pon := o.Pons[uint32(storedFlow.AccessIntfId)]
+			pon, err := o.GetPonById(uint32(storedFlow.AccessIntfId))
+			if err != nil {
+				oltLogger.WithFields(log.Fields{
+					"OnuId":  storedFlow.OnuId,
+					"IntfId": storedFlow.AccessIntfId,
+					"PONs":   olt.Pons,
+					"err":    err,
+				}).Error("PON-port-not-found")
+				return new(openolt.Empty), nil
+			}
 			onu, err := pon.GetOnuById(uint32(storedFlow.OnuId))
 			if err != nil {
 				oltLogger.WithFields(log.Fields{
 					"OnuId":  storedFlow.OnuId,
 					"IntfId": storedFlow.AccessIntfId,
 					"err":    err,
-				}).Error("ONU not found")
+				}).Error("ONU-not-found")
 				return new(openolt.Empty), nil
 			}
 			onu.DeleteFlow(flowKey)
@@ -1157,24 +1177,67 @@
 
 func (o *OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
 
-	devinfo := new(openolt.DeviceInfo)
-	devinfo.Vendor = common.Config.Olt.Vendor
-	devinfo.Model = common.Config.Olt.Model
-	devinfo.HardwareVersion = common.Config.Olt.HardwareVersion
-	devinfo.FirmwareVersion = common.Config.Olt.FirmwareVersion
-	devinfo.Technology = common.Config.Olt.Technology
-	devinfo.PonPorts = uint32(o.NumPon)
-	devinfo.OnuIdStart = 1
-	devinfo.OnuIdEnd = 255
-	devinfo.AllocIdStart = 1024
-	devinfo.AllocIdEnd = 16383
-	devinfo.GemportIdStart = 1024
-	devinfo.GemportIdEnd = 65535
-	devinfo.FlowIdStart = 1
-	devinfo.FlowIdEnd = 16383
-	devinfo.DeviceSerialNumber = o.SerialNumber
-	devinfo.DeviceId = common.Config.Olt.DeviceId
-	devinfo.PreviouslyConnected = o.PreviouslyConnected
+	oltLogger.WithFields(log.Fields{
+		"oltId":    o.ID,
+		"PonPorts": o.NumPon,
+	}).Info("OLT receives GetDeviceInfo call from VOLTHA")
+
+	intfIDs := []uint32{}
+	for i := 0; i < o.NumPon; i++ {
+		intfIDs = append(intfIDs, uint32(i))
+	}
+
+	devinfo := &openolt.DeviceInfo{
+		Vendor:              common.Config.Olt.Vendor,
+		Model:               common.Config.Olt.Model,
+		HardwareVersion:     common.Config.Olt.HardwareVersion,
+		FirmwareVersion:     common.Config.Olt.FirmwareVersion,
+		Technology:          common.Config.Olt.Technology,
+		PonPorts:            uint32(o.NumPon),
+		OnuIdStart:          onuIdStart,
+		OnuIdEnd:            onuIdEnd,
+		AllocIdStart:        allocIdStart,
+		AllocIdEnd:          allocIdEnd,
+		GemportIdStart:      gemportIdStart,
+		GemportIdEnd:        gemportIdEnd,
+		FlowIdStart:         flowIdStart,
+		FlowIdEnd:           flowIdEnd,
+		DeviceSerialNumber:  o.SerialNumber,
+		DeviceId:            common.Config.Olt.DeviceId,
+		PreviouslyConnected: o.PreviouslyConnected,
+		Ranges: []*openolt.DeviceInfo_DeviceResourceRanges{
+			{
+				IntfIds:    intfIDs,
+				Technology: common.Config.Olt.Technology,
+				Pools: []*openolt.DeviceInfo_DeviceResourceRanges_Pool{
+					{
+						Type:    openolt.DeviceInfo_DeviceResourceRanges_Pool_ONU_ID,
+						Sharing: openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF,
+						Start:   onuIdStart,
+						End:     onuIdEnd,
+					},
+					{
+						Type:    openolt.DeviceInfo_DeviceResourceRanges_Pool_ALLOC_ID,
+						Sharing: openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF,
+						Start:   allocIdStart,
+						End:     allocIdEnd,
+					},
+					{
+						Type:    openolt.DeviceInfo_DeviceResourceRanges_Pool_GEMPORT_ID,
+						Sharing: openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF,
+						Start:   gemportIdStart,
+						End:     gemportIdEnd,
+					},
+					{
+						Type:    openolt.DeviceInfo_DeviceResourceRanges_Pool_FLOW_ID,
+						Sharing: openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH,
+						Start:   flowIdStart,
+						End:     flowIdEnd,
+					},
+				},
+			},
+		},
+	}
 
 	oltLogger.WithFields(log.Fields{
 		"Vendor":              devinfo.Vendor,
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 9bfe805..fd7eca0 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -47,6 +47,41 @@
 	"module": "ONU",
 })
 
+const (
+	// ONU transitions
+	OnuTxInitialize            = "initialize"
+	OnuTxDiscover              = "discover"
+	OnuTxEnable                = "enable"
+	OnuTxDisable               = "disable"
+	OnuTxPonDisable            = "pon_disable"
+	OnuTxStartImageDownload    = "start_image_download"
+	OnuTxProgressImageDownload = "progress_image_download"
+	OnuTxCompleteImageDownload = "complete_image_download"
+	OnuTxFailImageDownload     = "fail_image_download"
+	OnuTxActivateImage         = "activate_image"
+	OnuTxCommitImage           = "commit_image"
+
+	// ONU States
+	OnuStateCreated                 = "created"
+	OnuStateInitialized             = "initialized"
+	OnuStateDiscovered              = "discovered"
+	OnuStateEnabled                 = "enabled"
+	OnuStateDisabled                = "disabled"
+	OnuStatePonDisabled             = "pon_disabled"
+	OnuStateImageDownloadStarted    = "image_download_started"
+	OnuStateImageDownloadInProgress = "image_download_in_progress"
+	OnuStateImageDownloadComplete   = "image_download_completed"
+	OnuStateImageDownloadError      = "image_download_error"
+	OnuStateImageActivated          = "software_image_activated"
+	OnuStateImageCommitted          = "software_image_committed"
+
+	// BBR ONU States and Transitions
+	BbrOnuTxSendEapolFlow    = "send_eapol_flow"
+	BbrOnuStateEapolFlowSent = "eapol_flow_sent"
+	BbrOnuTxSendDhcpFlow     = "send_dhcp_flow"
+	BbrOnuStateDhcpFlowSent  = "dhcp_flow_sent"
+)
+
 type FlowKey struct {
 	ID        uint64
 	Direction string
@@ -79,7 +114,11 @@
 	Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
 
 	// OMCI params
-	MibDataSync uint8
+	MibDataSync                   uint8
+	ImageSoftwareExpectedSections int
+	ImageSoftwareReceivedSections int
+	ActiveImageEntityId           uint16
+	CommittedImageEntityId        uint16
 
 	// OMCI params (Used in BBR)
 	tid       uint16
@@ -97,19 +136,22 @@
 func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
 
 	o := Onu{
-		ID:                  id,
-		PonPortID:           pon.ID,
-		PonPort:             pon,
-		PortNo:              0,
-		tid:                 0x1,
-		hpTid:               0x8000,
-		seqNumber:           0,
-		DoneChannel:         make(chan bool, 1),
-		GemPortAdded:        false,
-		DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
-		Flows:               []FlowKey{},
-		DiscoveryDelay:      delay,
-		MibDataSync:         0,
+		ID:                            id,
+		PonPortID:                     pon.ID,
+		PonPort:                       pon,
+		PortNo:                        0,
+		tid:                           0x1,
+		hpTid:                         0x8000,
+		seqNumber:                     0,
+		DoneChannel:                   make(chan bool, 1),
+		DiscoveryRetryDelay:           60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
+		Flows:                         []FlowKey{},
+		DiscoveryDelay:                delay,
+		MibDataSync:                   0,
+		ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
+		ImageSoftwareReceivedSections: 0,
+		ActiveImageEntityId:           0, // when we start the SoftwareImage with ID 0 is active and committed
+		CommittedImageEntityId:        0,
 	}
 	o.SerialNumber = o.NewSN(olt.ID, pon.ID, id)
 	// NOTE this state machine is used to track the operational
@@ -122,20 +164,27 @@
 
 	// NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
 	o.InternalState = fsm.NewFSM(
-		"created",
+		OnuStateCreated,
 		fsm.Events{
 			// DEVICE Lifecycle
-			{Name: "initialize", Src: []string{"created", "disabled", "pon_disabled"}, Dst: "initialized"},
-			{Name: "discover", Src: []string{"initialized"}, Dst: "discovered"},
-			{Name: "enable", Src: []string{"discovered", "pon_disabled"}, Dst: "enabled"},
+			{Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
+			{Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
+			{Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
 			// NOTE should disabled state be different for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
-			{Name: "disable", Src: []string{"enabled", "pon_disabled"}, Dst: "disabled"},
+			{Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
 			// ONU state when PON port is disabled but ONU is power ON(more states should be added in src?)
-			{Name: "pon_disabled", Src: []string{"enabled"}, Dst: "pon_disabled"},
+			{Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStatePonDisabled},
+			// Software Image Download related states
+			{Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError}, Dst: OnuStateImageDownloadStarted},
+			{Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
+			{Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
+			{Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
+			{Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
+			{Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
 			// BBR States
 			// TODO add start OMCI state
-			{Name: "send_eapol_flow", Src: []string{"initialized"}, Dst: "eapol_flow_sent"},
-			{Name: "send_dhcp_flow", Src: []string{"eapol_flow_sent"}, Dst: "dhcp_flow_sent"},
+			{Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
+			{Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
 		},
 		fsm.Callbacks{
 			"enter_state": func(e *fsm.Event) {
@@ -145,7 +194,7 @@
 				// create new channel for ProcessOnuMessages Go routine
 				o.Channel = make(chan bbsim.Message, 2048)
 
-				if err := o.OperState.Event("enable"); err != nil {
+				if err := o.OperState.Event(OnuTxEnable); err != nil {
 					onuLogger.WithFields(log.Fields{
 						"OnuId":  o.ID,
 						"IntfId": o.PonPortID,
@@ -421,7 +470,7 @@
 	// after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
 	go func(delay time.Duration) {
 		time.Sleep(delay)
-		if o.InternalState.Current() == "discovered" {
+		if o.InternalState.Current() == OnuStateDiscovered {
 			o.sendOnuDiscIndication(msg, stream)
 		}
 	}(o.DiscoveryRetryDelay)
@@ -490,7 +539,7 @@
 
 	// TODO if it's the last ONU on the PON, then send a PON LOS
 
-	if err := o.InternalState.Event("disable"); err != nil {
+	if err := o.InternalState.Event(OnuTxDisable); err != nil {
 		onuLogger.WithFields(log.Fields{
 			"OnuId":  o.ID,
 			"IntfId": o.PonPortID,
@@ -506,8 +555,8 @@
 	intitalState := o.InternalState.Current()
 
 	// initialize the ONU
-	if intitalState == "created" || intitalState == "disabled" {
-		if err := o.InternalState.Event("initialize"); err != nil {
+	if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
+		if err := o.InternalState.Event(OnuTxInitialize); err != nil {
 			onuLogger.WithFields(log.Fields{
 				"OnuId":  o.ID,
 				"IntfId": o.PonPortID,
@@ -534,7 +583,7 @@
 	}
 
 	// Send a ONU Discovery indication
-	if err := o.InternalState.Event("discover"); err != nil {
+	if err := o.InternalState.Event(OnuTxDiscover); err != nil {
 		onuLogger.WithFields(log.Fields{
 			"OnuId":  o.ID,
 			"IntfId": o.PonPortID,
@@ -546,8 +595,8 @@
 	// move o directly to enable state only when its a powercycle case
 	// in case of first time o poweron o will be moved to enable on
 	// receiving ActivateOnu request from openolt adapter
-	if intitalState == "disabled" {
-		if err := o.InternalState.Event("enable"); err != nil {
+	if intitalState == OnuStateDisabled {
+		if err := o.InternalState.Event(OnuTxEnable); err != nil {
 			onuLogger.WithFields(log.Fields{
 				"OnuId":  o.ID,
 				"IntfId": o.PonPortID,
@@ -627,7 +676,7 @@
 		log.WithFields(log.Fields{
 			"IntfId":       o.PonPortID,
 			"SerialNumber": o.Sn(),
-			"omciPacket":   msg.OmciMsg.Pkt,
+			"omciPacket":   omcilib.HexDecode(msg.OmciMsg.Pkt),
 		}).Error("cannot-parse-OMCI-packet")
 	}
 
@@ -656,7 +705,7 @@
 	case omci.MibUploadNextRequestType:
 		responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg, o.MibDataSync)
 	case omci.GetRequestType:
-		responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber, o.MibDataSync)
+		responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId)
 	case omci.SetRequestType:
 		if responsePkt, errResp = omcilib.CreateSetResponse(omciPkt, omciMsg); errResp == nil {
 			o.MibDataSync++
@@ -699,20 +748,17 @@
 		responsePkt, _ = omcilib.CreateRebootResponse(omciPkt, omciMsg)
 
 		// powercycle the ONU
+		// we run this in a separate goroutine so that
+		// the RebootRequestResponse is sent to VOLTHA
 		go func() {
-			// we run this in a separate goroutine so that
-			// the RebootRequestResponse is sent to VOLTHA
-			onuLogger.WithFields(log.Fields{
-				"IntfId":       o.PonPortID,
-				"SerialNumber": o.Sn(),
-			}).Debug("shutting-down-onu-for-omci-reboot")
-			_ = o.HandleShutdownONU()
-			time.Sleep(10 * time.Second)
-			onuLogger.WithFields(log.Fields{
-				"IntfId":       o.PonPortID,
-				"SerialNumber": o.Sn(),
-			}).Debug("power-on-onu-for-omci-reboot")
-			_ = o.HandlePowerOnONU()
+			if err := o.Reboot(10 * time.Second); err != nil {
+				log.WithFields(log.Fields{
+					"IntfId":       o.PonPortID,
+					"OnuId":        o.ID,
+					"SerialNumber": o.Sn(),
+					"err":          err,
+				}).Error("cannot-reboot-onu-after-omci-reboot-request")
+			}
 		}()
 	case omci.TestRequestType:
 
@@ -726,6 +772,7 @@
 			if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
 				onuLogger.WithFields(log.Fields{
 					"IntfId":       o.PonPortID,
+					"OnuId":        o.ID,
 					"SerialNumber": o.Sn(),
 					"omciPacket":   msg.OmciMsg.Pkt,
 					"msg":          msg,
@@ -736,8 +783,187 @@
 	case omci.SynchronizeTimeRequestType:
 		// MDS counter increment is not required for this message type
 		responsePkt, _ = omcilib.CreateSyncTimeResponse(omciPkt, omciMsg)
+	case omci.StartSoftwareDownloadRequestType:
+
+		o.ImageSoftwareReceivedSections = 0
+
+		o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(omciPkt)
+
+		if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(omciPkt, omciMsg); errResp == nil {
+			o.MibDataSync++
+			if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
+				onuLogger.WithFields(log.Fields{
+					"OnuId":  o.ID,
+					"IntfId": o.PonPortID,
+					"OnuSn":  o.Sn(),
+					"Err":    err.Error(),
+				}).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
+			}
+		} else {
+			onuLogger.WithFields(log.Fields{
+				"OmciMsgType":  omciMsg.MessageType,
+				"TransCorrId":  omciMsg.TransactionID,
+				"Err":          err.Error(),
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+			}).Error("error-while-processing-start-software-download-request")
+		}
+	case omci.DownloadSectionRequestType:
+		if msgObj, err := omcilib.ParseDownloadSectionRequest(omciPkt); err == nil {
+			onuLogger.WithFields(log.Fields{
+				"OmciMsgType":    omciMsg.MessageType,
+				"TransCorrId":    omciMsg.TransactionID,
+				"EntityInstance": msgObj.EntityInstance,
+				"SectionNumber":  msgObj.SectionNumber,
+				"SectionData":    msgObj.SectionData,
+			}).Trace("received-download-section-request")
+			o.ImageSoftwareReceivedSections++
+			if o.InternalState.Current() != OnuStateImageDownloadInProgress {
+				if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
+					onuLogger.WithFields(log.Fields{
+						"OnuId":  o.ID,
+						"IntfId": o.PonPortID,
+						"OnuSn":  o.Sn(),
+						"Err":    err.Error(),
+					}).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
+				}
+			}
+		}
+	case omci.DownloadSectionRequestWithResponseType:
+		// NOTE we only need to respond if an ACK is requested
+		responsePkt, err = omcilib.CreateDownloadSectionResponse(omciPkt, omciMsg)
+		if err != nil {
+			onuLogger.WithFields(log.Fields{
+				"OmciMsgType":  omciMsg.MessageType,
+				"TransCorrId":  omciMsg.TransactionID,
+				"Err":          err.Error(),
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+			}).Error("error-while-processing-create-download-section-response")
+			return
+		}
+		o.ImageSoftwareReceivedSections++
+
+	case omci.EndSoftwareDownloadRequestType:
+
+		// In the startSoftwareDownload we get the image size and the window size.
+		// We calculate how many DownloadSection we should receive and validate
+		// that we got the correct amount when we receive this message
+		success := true
+		if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
+			onuLogger.WithFields(log.Fields{
+				"OnuId":            o.ID,
+				"IntfId":           o.PonPortID,
+				"OnuSn":            o.Sn(),
+				"ExpectedSections": o.ImageSoftwareExpectedSections,
+				"ReceivedSections": o.ImageSoftwareReceivedSections,
+			}).Errorf("onu-did-not-receive-all-image-sections")
+			success = false
+		}
+
+		if success {
+			if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.Success); errResp == nil {
+				o.MibDataSync++
+				if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
+					onuLogger.WithFields(log.Fields{
+						"OnuId":  o.ID,
+						"IntfId": o.PonPortID,
+						"OnuSn":  o.Sn(),
+						"Err":    err.Error(),
+					}).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
+				}
+			} else {
+				onuLogger.WithFields(log.Fields{
+					"OmciMsgType":  omciMsg.MessageType,
+					"TransCorrId":  omciMsg.TransactionID,
+					"Err":          err.Error(),
+					"IntfId":       o.PonPortID,
+					"SerialNumber": o.Sn(),
+				}).Error("error-while-processing-end-software-download-request")
+			}
+		} else {
+			if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.ProcessingError); errResp == nil {
+				if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
+					onuLogger.WithFields(log.Fields{
+						"OnuId":  o.ID,
+						"IntfId": o.PonPortID,
+						"OnuSn":  o.Sn(),
+						"Err":    err.Error(),
+					}).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
+				}
+			}
+		}
+
+	case omci.ActivateSoftwareRequestType:
+		if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(omciPkt, omciMsg); errResp == nil {
+			o.MibDataSync++
+			if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
+				onuLogger.WithFields(log.Fields{
+					"OnuId":  o.ID,
+					"IntfId": o.PonPortID,
+					"OnuSn":  o.Sn(),
+					"Err":    err.Error(),
+				}).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
+			}
+			if msgObj, err := omcilib.ParseActivateSoftwareRequest(omciPkt); err == nil {
+				o.ActiveImageEntityId = msgObj.EntityInstance
+			} else {
+				onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
+			}
+			onuLogger.WithFields(log.Fields{
+				"OnuId":                  o.ID,
+				"IntfId":                 o.PonPortID,
+				"OnuSn":                  o.Sn(),
+				"ActiveImageEntityId":    o.ActiveImageEntityId,
+				"CommittedImageEntityId": o.CommittedImageEntityId,
+			}).Info("onu-software-image-activated")
+
+			// powercycle the ONU
+			// we run this in a separate goroutine so that
+			// the ActivateSoftwareResponse is sent to VOLTHA
+			// NOTE do we need to wait before rebooting?
+			go func() {
+				if err := o.Reboot(10 * time.Second); err != nil {
+					log.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"OnuId":        o.ID,
+						"SerialNumber": o.Sn(),
+						"err":          err,
+					}).Error("cannot-reboot-onu-after-omci-activate-software-request")
+				}
+			}()
+		}
+	case omci.CommitSoftwareRequestType:
+		if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(omciPkt, omciMsg); errResp == nil {
+			o.MibDataSync++
+			if msgObj, err := omcilib.ParseCommitSoftwareRequest(omciPkt); err == nil {
+				// TODO validate that the image to commit is:
+				// - active
+				// - not already committed
+				o.CommittedImageEntityId = msgObj.EntityInstance
+			} else {
+				onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
+			}
+			if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
+				onuLogger.WithFields(log.Fields{
+					"OnuId":  o.ID,
+					"IntfId": o.PonPortID,
+					"OnuSn":  o.Sn(),
+					"Err":    err.Error(),
+				}).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
+			}
+			onuLogger.WithFields(log.Fields{
+				"OnuId":                  o.ID,
+				"IntfId":                 o.PonPortID,
+				"OnuSn":                  o.Sn(),
+				"ActiveImageEntityId":    o.ActiveImageEntityId,
+				"CommittedImageEntityId": o.CommittedImageEntityId,
+			}).Info("onu-software-image-committed")
+		}
 	default:
-		log.WithFields(log.Fields{
+		onuLogger.WithFields(log.Fields{
+			"omciBytes":    hex.EncodeToString(omciPkt.Data()),
+			"omciPkt":      omciPkt,
 			"omciMsgType":  omciMsg.MessageType,
 			"transCorrId":  omciMsg.TransactionID,
 			"IntfId":       o.PonPortID,
@@ -901,12 +1127,33 @@
 
 		// check if ONU delete is performed and
 		// terminate the ONU's ProcessOnuMessages Go routine
-		if o.InternalState.Current() == "disabled" {
+		if o.InternalState.Current() == OnuStateDisabled {
 			close(o.Channel)
 		}
 	}
 }
 
+func (o *Onu) Reboot(timeout time.Duration) error {
+	onuLogger.WithFields(log.Fields{
+		"IntfId":       o.PonPortID,
+		"OnuId":        o.ID,
+		"SerialNumber": o.Sn(),
+	}).Debug("shutting-down-onu")
+	if err := o.HandleShutdownONU(); err != nil {
+		return err
+	}
+	time.Sleep(timeout)
+	onuLogger.WithFields(log.Fields{
+		"IntfId":       o.PonPortID,
+		"OnuId":        o.ID,
+		"SerialNumber": o.Sn(),
+	}).Debug("power-on-onu")
+	if err := o.HandlePowerOnONU(); err != nil {
+		return err
+	}
+	return nil
+}
+
 // BBR methods
 
 func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
@@ -1017,7 +1264,7 @@
 			sendOmciMsg(gemReq, o.PonPortID, o.ID, o.SerialNumber, "CreateGemPortRequest", client)
 			o.GemPortAdded = true
 		} else {
-			if err := o.InternalState.Event("send_eapol_flow"); err != nil {
+			if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
 				onuLogger.WithFields(log.Fields{
 					"OnuId":  o.ID,
 					"IntfId": o.PonPortID,
@@ -1144,20 +1391,20 @@
 	}).Debug("Send ONU Re-Discovery")
 
 	// ONU Re-Discovery
-	if err := onu.InternalState.Event("initialize"); err != nil {
+	if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
 		log.WithFields(log.Fields{
 			"IntfId": onu.PonPortID,
 			"OnuSn":  onu.Sn(),
 			"OnuId":  onu.ID,
-		}).Infof("Failed to transition ONU to initialized state: %s", err.Error())
+		}).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
 	}
 
-	if err := onu.InternalState.Event("discover"); err != nil {
+	if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
 		log.WithFields(log.Fields{
 			"IntfId": onu.PonPortID,
 			"OnuSn":  onu.Sn(),
 			"OnuId":  onu.ID,
-		}).Infof("Failed to transition ONU to discovered state: %s", err.Error())
+		}).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
 	}
 }
 
diff --git a/internal/bbsim/devices/onu_indications_test.go b/internal/bbsim/devices/onu_indications_test.go
index 1a34da1..04af678 100644
--- a/internal/bbsim/devices/onu_indications_test.go
+++ b/internal/bbsim/devices/onu_indications_test.go
@@ -58,8 +58,8 @@
 	}
 	ctx, cancel := context.WithCancel(context.TODO())
 	go onu.ProcessOnuMessages(ctx, stream, nil)
-	onu.InternalState.SetState("initialized")
-	_ = onu.InternalState.Event("discover")
+	onu.InternalState.SetState(OnuTxInitialize)
+	_ = onu.InternalState.Event(OnuTxDiscover)
 
 	select {
 	default:
@@ -83,8 +83,8 @@
 	}
 	ctx, cancel := context.WithCancel(context.TODO())
 	go onu.ProcessOnuMessages(ctx, stream, nil)
-	onu.InternalState.SetState("initialized")
-	_ = onu.InternalState.Event("discover")
+	onu.InternalState.SetState(OnuStateInitialized)
+	_ = onu.InternalState.Event(OnuTxDiscover)
 
 	select {
 	default:
@@ -106,8 +106,8 @@
 	}
 	ctx, cancel := context.WithCancel(context.TODO())
 	go onu.ProcessOnuMessages(ctx, stream, nil)
-	onu.InternalState.SetState("initialized")
-	_ = onu.InternalState.Event("discover")
+	onu.InternalState.SetState(OnuStateInitialized)
+	_ = onu.InternalState.Event(OnuTxDiscover)
 
 	go func() {
 		for calls := range stream.channel {
diff --git a/internal/bbsim/devices/onu_state_machine_test.go b/internal/bbsim/devices/onu_state_machine_test.go
index b48b286..6f62540 100644
--- a/internal/bbsim/devices/onu_state_machine_test.go
+++ b/internal/bbsim/devices/onu_state_machine_test.go
@@ -28,13 +28,13 @@
 	_ = onu.InternalState.Event("discover")
 	assert.Equal(t, onu.InternalState.Current(), "discovered")
 	_ = onu.InternalState.Event("enable")
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 }
 
 func Test_Onu_StateMachine_disable(t *testing.T) {
 	onu := createTestOnu()
-	onu.InternalState.SetState("enabled")
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	onu.InternalState.SetState(OnuStateEnabled)
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	onu.PortNo = 16
 	onu.GemPortAdded = true
@@ -43,8 +43,8 @@
 		{ID: 2, Direction: "downstream"},
 	}
 
-	_ = onu.InternalState.Event("disable")
-	assert.Equal(t, onu.InternalState.Current(), "disabled")
+	_ = onu.InternalState.Event(OnuTxDisable)
+	assert.Equal(t, onu.InternalState.Current(), OnuStateDisabled)
 
 	assert.Equal(t, onu.GemPortAdded, false)
 	assert.Equal(t, onu.PortNo, uint32(0))
@@ -58,15 +58,15 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("enabled")
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	onu.InternalState.SetState(OnuStateEnabled)
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	// fail as no EapolFlow has been received
 	err := onu.InternalState.Event("start_auth")
 	if err == nil {
 		t.Fatal("can't start EAPOL without EapolFlow")
 	}
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 	assert.Equal(t, err.Error(), "transition canceled with error: cannot-go-to-auth-started-as-eapol-flow-is-missing")
 }
 
@@ -74,15 +74,15 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("enabled")
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	onu.InternalState.SetState(OnuStateEnabled)
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	// fail has no GemPort has been set
 	err := onu.InternalState.Event("start_auth")
 	if err == nil {
 		t.Fatal("can't start EAPOL without GemPort")
 	}
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 	assert.Equal(t, err.Error(), "transition canceled with error: cannot-go-to-auth-started-as-gemport-is-missing")
 
 }
@@ -91,8 +91,8 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("enabled")
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	onu.InternalState.SetState(OnuStateEnabled)
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	// succeed
 	onu.GemPortAdded = true
@@ -133,14 +133,14 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("enabled")
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	onu.InternalState.SetState(OnuStateEnabled)
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	err := onu.InternalState.Event("start_dhcp")
 	if err == nil {
 		t.Fail()
 	}
-	assert.Equal(t, onu.InternalState.Current(), "enabled")
+	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 	assert.Equal(t, err.Error(), "transition canceled with error: cannot-go-to-dhcp-started-as-authentication-is-required")
 }
 
diff --git a/internal/bbsim/devices/onu_test_helpers.go b/internal/bbsim/devices/onu_test_helpers.go
index c08d9a8..f0d5dab 100644
--- a/internal/bbsim/devices/onu_test_helpers.go
+++ b/internal/bbsim/devices/onu_test_helpers.go
@@ -161,7 +161,7 @@
 	}
 	onu := CreateONU(&olt, &pon, 1, time.Duration(1*time.Millisecond), true)
 	// NOTE we need this in order to create the OnuChannel
-	_ = onu.InternalState.Event("initialize")
+	_ = onu.InternalState.Event(OnuTxInitialize)
 	onu.DiscoveryRetryDelay = 100 * time.Millisecond
 	return onu
 }
diff --git a/internal/bbsim/devices/pon.go b/internal/bbsim/devices/pon.go
index 6910ece..1e0483d 100644
--- a/internal/bbsim/devices/pon.go
+++ b/internal/bbsim/devices/pon.go
@@ -65,11 +65,11 @@
 				if e.Src == "created" {
 					if olt.ControlledActivation == Default || olt.ControlledActivation == OnlyPON {
 						for _, onu := range ponPort.Onus {
-							if err := onu.InternalState.Event("initialize"); err != nil {
+							if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
 								log.Errorf("Error initializing ONU: %v", err)
 								continue
 							}
-							if err := onu.InternalState.Event("discover"); err != nil {
+							if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
 								log.Errorf("Error discover ONU: %v", err)
 							}
 						}
@@ -78,7 +78,7 @@
 					if ponPort.Olt.ControlledActivation == OnlyONU || ponPort.Olt.ControlledActivation == Both {
 						// if ONUs are manually activated then only initialize them
 						for _, onu := range ponPort.Onus {
-							if err := onu.InternalState.Event("initialize"); err != nil {
+							if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
 								log.WithFields(log.Fields{
 									"Err":    err,
 									"OnuSn":  onu.Sn(),
@@ -89,16 +89,16 @@
 						}
 					} else {
 						for _, onu := range ponPort.Onus {
-							if onu.InternalState.Current() == "pon_disabled" {
-								if err := onu.InternalState.Event("enable"); err != nil {
+							if onu.InternalState.Current() == OnuStatePonDisabled {
+								if err := onu.InternalState.Event(OnuStateEnabled); err != nil {
 									log.WithFields(log.Fields{
 										"Err":    err,
 										"OnuSn":  onu.Sn(),
 										"IntfId": onu.PonPortID,
 									}).Error("Error enabling ONU")
 								}
-							} else if onu.InternalState.Current() == "disabled" {
-								if err := onu.InternalState.Event("initialize"); err != nil {
+							} else if onu.InternalState.Current() == OnuStateDisabled {
+								if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
 									log.WithFields(log.Fields{
 										"Err":    err,
 										"OnuSn":  onu.Sn(),
@@ -106,15 +106,15 @@
 									}).Error("Error initializing ONU")
 									continue
 								}
-								if err := onu.InternalState.Event("discover"); err != nil {
+								if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
 									log.WithFields(log.Fields{
 										"Err":    err,
 										"OnuSn":  onu.Sn(),
 										"IntfId": onu.PonPortID,
 									}).Error("Error discovering ONU")
 								}
-							} else if onu.InternalState.Current() == "initialized" {
-								if err := onu.InternalState.Event("discover"); err != nil {
+							} else if onu.InternalState.Current() == OnuStateInitialized {
+								if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
 									log.WithFields(log.Fields{
 										"Err":    err,
 										"OnuSn":  onu.Sn(),
@@ -135,11 +135,11 @@
 			},
 			"enter_disabled": func(e *fsm.Event) {
 				for _, onu := range ponPort.Onus {
-					if onu.InternalState.Current() == "initialized" || onu.InternalState.Current() == "disabled" {
+					if onu.InternalState.Current() == OnuStateInitialized || onu.InternalState.Current() == OnuStateDisabled {
 						continue
 					}
-					if err := onu.InternalState.Event("pon_disabled"); err != nil {
-						oltLogger.Errorf("Failed to move ONU in pon_disabled states: %v", err)
+					if err := onu.InternalState.Event(OnuTxPonDisable); err != nil {
+						oltLogger.Errorf("Failed to move ONU in %s states: %v", OnuStatePonDisabled, err)
 					}
 				}
 			},
@@ -192,7 +192,7 @@
 func (p PonPort) GetNumOfActiveOnus() uint32 {
 	var count uint32 = 0
 	for _, onu := range p.Onus {
-		if onu.InternalState.Current() == "initialized" || onu.InternalState.Current() == "created" || onu.InternalState.Current() == "disabled" {
+		if onu.InternalState.Current() == OnuStateInitialized || onu.InternalState.Current() == OnuStateCreated || onu.InternalState.Current() == OnuStateDisabled {
 			continue
 		}
 		count++
diff --git a/internal/bbsim/responders/sadis/sadis.go b/internal/bbsim/responders/sadis/sadis.go
index 5b71a94..4b9ccb3 100644
--- a/internal/bbsim/responders/sadis/sadis.go
+++ b/internal/bbsim/responders/sadis/sadis.go
@@ -20,7 +20,6 @@
 	"encoding/json"
 	"net/http"
 	"strings"
-	"sync"
 
 	"github.com/gorilla/mux"
 	"github.com/opencord/bbsim/internal/bbsim/devices"
@@ -32,8 +31,8 @@
 	"module": "SADIS",
 })
 
-type sadisServer struct {
-	olt *devices.OltDevice
+type SadisServer struct {
+	Olt *devices.OltDevice
 }
 
 // bandwidthProfiles contains some dummy profiles
@@ -228,7 +227,7 @@
 	return bwp
 }
 
-func (s *sadisServer) ServeBaseConfig(w http.ResponseWriter, r *http.Request) {
+func (s *SadisServer) ServeBaseConfig(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.WriteHeader(http.StatusOK)
 	vars := mux.Vars(r)
@@ -239,7 +238,7 @@
 		return
 	}
 
-	sadisConf := GetSadisConfig(s.olt, vars["version"])
+	sadisConf := GetSadisConfig(s.Olt, vars["version"])
 
 	sadisJSON, _ := json.Marshal(sadisConf)
 
@@ -247,17 +246,17 @@
 
 }
 
-func (s *sadisServer) ServeStaticConfig(w http.ResponseWriter, r *http.Request) {
+func (s *SadisServer) ServeStaticConfig(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.WriteHeader(http.StatusOK)
 	vars := mux.Vars(r)
-	sadisConf := GetSadisConfig(s.olt, vars["version"])
+	sadisConf := GetSadisConfig(s.Olt, vars["version"])
 
 	sadisConf.Sadis.Integration.URL = ""
-	for i := range s.olt.Pons {
-		for _, onu := range s.olt.Pons[i].Onus {
+	for i := range s.Olt.Pons {
+		for _, onu := range s.Olt.Pons[i].Onus {
 			if vars["version"] == "v2" {
-				sonuV2, _ := GetOnuEntryV2(s.olt, onu, "1")
+				sonuV2, _ := GetOnuEntryV2(s.Olt, onu, "1")
 				sadisConf.Sadis.Entries = append(sadisConf.Sadis.Entries, sonuV2)
 			}
 		}
@@ -273,17 +272,17 @@
 
 }
 
-func (s *sadisServer) ServeEntry(w http.ResponseWriter, r *http.Request) {
+func (s *SadisServer) ServeEntry(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	vars := mux.Vars(r)
 
 	// check if the requested ID is for the OLT
-	if s.olt.SerialNumber == vars["ID"] {
+	if s.Olt.SerialNumber == vars["ID"] {
 		sadisLogger.WithFields(log.Fields{
-			"OltSn": s.olt.SerialNumber,
+			"OltSn": s.Olt.SerialNumber,
 		}).Debug("Received SADIS OLT request")
 
-		sadisConf, _ := GetOltEntry(s.olt)
+		sadisConf, _ := GetOltEntry(s.Olt)
 
 		w.WriteHeader(http.StatusOK)
 		_ = json.NewEncoder(w).Encode(sadisConf)
@@ -299,7 +298,7 @@
 	}
 	sn, uni := i[0], i[len(i)-1]
 
-	onu, err := s.olt.FindOnuBySn(sn)
+	onu, err := s.Olt.FindOnuBySn(sn)
 	if err != nil {
 		w.WriteHeader(http.StatusNotFound)
 		_, _ = w.Write([]byte("{}"))
@@ -322,13 +321,13 @@
 		_ = json.NewEncoder(w).Encode("Sadis v1 is not supported anymore, please go back to an earlier BBSim version")
 	} else if vars["version"] == "v2" {
 		w.WriteHeader(http.StatusOK)
-		sadisConf, _ := GetOnuEntryV2(s.olt, onu, uni)
+		sadisConf, _ := GetOnuEntryV2(s.Olt, onu, uni)
 		_ = json.NewEncoder(w).Encode(sadisConf)
 	}
 
 }
 
-func (s *sadisServer) ServeBWPEntry(w http.ResponseWriter, r *http.Request) {
+func (s *SadisServer) ServeBWPEntry(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	vars := mux.Vars(r)
 	id := vars["ID"]
@@ -352,22 +351,3 @@
 	w.WriteHeader(http.StatusNotFound)
 	_, _ = w.Write([]byte("{}"))
 }
-
-// StartRestServer starts REST server which returns a SADIS configuration for the currently simulated OLT
-func StartRestServer(olt *devices.OltDevice, wg *sync.WaitGroup) {
-	addr := common.Config.BBSim.SadisRestAddress
-	sadisLogger.Infof("SADIS server listening on %s", addr)
-	s := &sadisServer{
-		olt: olt,
-	}
-
-	router := mux.NewRouter().StrictSlash(true)
-	router.HandleFunc("/{version}/cfg", s.ServeBaseConfig)
-	router.HandleFunc("/{version}/static", s.ServeStaticConfig)
-	router.HandleFunc("/{version}/subscribers/{ID}", s.ServeEntry)
-	router.HandleFunc("/{version}/bandwidthprofiles/{ID}", s.ServeBWPEntry)
-
-	log.Fatal(http.ListenAndServe(addr, router))
-
-	wg.Done()
-}
diff --git a/internal/bbsim/responders/webserver/webserver.go b/internal/bbsim/responders/webserver/webserver.go
new file mode 100644
index 0000000..2c5d29b
--- /dev/null
+++ b/internal/bbsim/responders/webserver/webserver.go
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package webserver
+
+import (
+	"github.com/gorilla/mux"
+	"github.com/opencord/bbsim/internal/bbsim/devices"
+	"github.com/opencord/bbsim/internal/bbsim/responders/sadis"
+	"github.com/opencord/bbsim/internal/common"
+	log "github.com/sirupsen/logrus"
+	"net/http"
+	"sync"
+)
+
+var logger = log.WithFields(log.Fields{
+	"module": "WEBSERVER",
+})
+
+// StartRestServer starts REST server which esposes:
+// - a SADIS configuration for the currently simulated OLT
+// - static files for software image download
+func StartRestServer(olt *devices.OltDevice, wg *sync.WaitGroup) {
+	addr := common.Config.BBSim.SadisRestAddress
+	logger.Infof("WEBSERVER server listening on %s", addr)
+	s := &sadis.SadisServer{
+		Olt: olt,
+	}
+
+	router := mux.NewRouter().StrictSlash(true)
+
+	// sadis routes
+	router.HandleFunc("/{version}/cfg", s.ServeBaseConfig)
+	router.HandleFunc("/{version}/static", s.ServeStaticConfig)
+	router.HandleFunc("/{version}/subscribers/{ID}", s.ServeEntry)
+	router.HandleFunc("/{version}/bandwidthprofiles/{ID}", s.ServeBWPEntry)
+
+	// Choose the folder to serve (this is the location inside the container)
+	staticDir := "/app/configs/"
+
+	// Create the route
+	router.
+		PathPrefix("/images/").
+		Handler(http.StripPrefix("/images/", http.FileServer(http.Dir(staticDir))))
+
+	log.Fatal(http.ListenAndServe(addr, router))
+
+	wg.Done()
+}
diff --git a/internal/bbsimctl/commands/onu.go b/internal/bbsimctl/commands/onu.go
index da841cd..78923e0 100644
--- a/internal/bbsimctl/commands/onu.go
+++ b/internal/bbsimctl/commands/onu.go
@@ -34,8 +34,8 @@
 )
 
 const (
-	DEFAULT_ONU_DEVICE_HEADER_FORMAT               = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}"
-	DEFAULT_ONU_DEVICE_HEADER_FORMAT_WITH_SERVICES = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .Services }}"
+	DEFAULT_ONU_DEVICE_HEADER_FORMAT               = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .ImageSoftwareExpectedSections }}\t{{ .ImageSoftwareReceivedSections }}\t{{ .ActiveImageEntityId }}\t{{ .CommittedImageEntityId }}"
+	DEFAULT_ONU_DEVICE_HEADER_FORMAT_WITH_SERVICES = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .PortNo }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}\t{{ .ImageSoftwareExpectedSections }}\t{{ .ImageSoftwareReceivedSections }}\t{{ .ActiveImageEntityId }}\t{{ .CommittedImageEntityId }}\t{{ .Services }}"
 )
 
 type OnuSnString string
diff --git a/internal/common/omci/get.go b/internal/common/omci/get.go
index e47dc0c..5172f60 100644
--- a/internal/common/omci/get.go
+++ b/internal/common/omci/get.go
@@ -45,7 +45,7 @@
 	return msgObj, nil
 }
 
-func CreateGetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, onuSn *openolt.SerialNumber, mds uint8) ([]byte, error) {
+func CreateGetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, onuSn *openolt.SerialNumber, mds uint8, activeImageEntityId uint16, committedImageEntityId uint16) ([]byte, error) {
 
 	msgObj, err := ParseGetRequest(omciPkt)
 
@@ -66,7 +66,7 @@
 	case me.OnuGClassID:
 		response = createOnugResponse(msgObj.AttributeMask, msgObj.EntityInstance, onuSn)
 	case me.SoftwareImageClassID:
-		response = createSoftwareImageResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+		response = createSoftwareImageResponse(msgObj.AttributeMask, msgObj.EntityInstance, activeImageEntityId, committedImageEntityId)
 	case me.IpHostConfigDataClassID:
 		response = createIpHostResponse(msgObj.AttributeMask, msgObj.EntityInstance)
 	case me.UniGClassID:
@@ -200,9 +200,24 @@
 	//}
 }
 
-func createSoftwareImageResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
+func createSoftwareImageResponse(attributeMask uint16, entityInstance uint16, activeImageEntityId uint16, committedImageEntityId uint16) *omci.GetResponse {
+
+	omciLogger.WithFields(log.Fields{
+		"EntityInstance": entityInstance,
+	}).Info("received-get-software-image-request")
+
+	// Only one image can be active and committed
+	committed := 0
+	active := 0
+	if entityInstance == activeImageEntityId {
+		active = 1
+	}
+	if entityInstance == committedImageEntityId {
+		committed = 1
+	}
+
 	// NOTE that we need send the response for the correct ME Instance or the adapter won't process it
-	return &omci.GetResponse{
+	res := &omci.GetResponse{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    me.SoftwareImageClassID,
 			EntityInstance: entityInstance,
@@ -210,8 +225,8 @@
 		Attributes: me.AttributeValueMap{
 			"ManagedEntityId": 0,
 			"Version":         toOctets("00000000000001", 14),
-			"IsCommitted":     1,
-			"IsActive":        1,
+			"IsCommitted":     committed,
+			"IsActive":        active,
 			"IsValid":         1,
 			"ProductCode":     toOctets("product-code", 25),
 			"ImageHash":       toOctets("broadband-sim", 16),
@@ -219,6 +234,15 @@
 		Result:        me.Success,
 		AttributeMask: attributeMask,
 	}
+
+	omciLogger.WithFields(log.Fields{
+		"omciMessage": res,
+		"entityId":    entityInstance,
+		"active":      active,
+		"committed":   committed,
+	}).Info("Reporting SoftwareImage")
+
+	return res
 }
 
 func createIpHostResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
diff --git a/internal/common/omci/image.go b/internal/common/omci/image.go
new file mode 100644
index 0000000..8480ecb
--- /dev/null
+++ b/internal/common/omci/image.go
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"encoding/hex"
+	"errors"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	log "github.com/sirupsen/logrus"
+	"math"
+	"strconv"
+)
+
+func ParseStartSoftwareDownloadRequest(omciPkt gopacket.Packet) (*omci.StartSoftwareDownloadRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeStartSoftwareDownloadRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeStartSoftwareDownloadRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeStartSoftwareDownloadRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func ParseDownloadSectionRequest(omciPkt gopacket.Packet) (*omci.DownloadSectionRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeDownloadSectionRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeDownloadSectionRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.DownloadSectionRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeDownloadSectionRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func ParseEndSoftwareDownloadRequest(omciPkt gopacket.Packet) (*omci.EndSoftwareDownloadRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeEndSoftwareDownloadRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeEndSoftwareDownloadRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeEndSoftwareDownloadRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func ParseActivateSoftwareRequest(omciPkt gopacket.Packet) (*omci.ActivateSoftwareRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeActivateSoftwareRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeActivateSoftwareRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.ActivateSoftwareRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeActivateSoftwareRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func ParseCommitSoftwareRequest(omciPkt gopacket.Packet) (*omci.CommitSoftwareRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeCommitSoftwareRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeCommitSoftwareRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.CommitSoftwareRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeCommitSoftwareRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func CreateStartSoftwareDownloadResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+	responeCode := me.Success
+	msgObj, err := ParseStartSoftwareDownloadRequest(omciPkt)
+	if err != nil {
+		responeCode = me.ProcessingError
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"OmciMsgType":          omciMsg.MessageType,
+		"TransCorrId":          omciMsg.TransactionID,
+		"EntityInstance":       msgObj.EntityInstance,
+		"WindowSize":           msgObj.WindowSize,
+		"ImageSize":            msgObj.ImageSize,
+		"NumberOfCircuitPacks": msgObj.NumberOfCircuitPacks,
+		"CircuitPacks":         msgObj.CircuitPacks,
+	}).Debug("received-start-software-download-request")
+
+	response := &omci.StartSoftwareDownloadResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		WindowSize:        msgObj.WindowSize,
+		Result:            responeCode,
+		NumberOfInstances: 0,                        // NOTE this can't be bigger than 0 this we can populate downloadResults
+		MeResults:         []omci.DownloadResults{}, // FIXME downloadResults is not exported
+	}
+
+	pkt, err := Serialize(omci.StartSoftwareDownloadResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Error("cannot-Serialize-CreateResponse")
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-start-software-download-response")
+
+	return pkt, nil
+}
+
+func CreateDownloadSectionResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+	msgObj, err := ParseDownloadSectionRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"OmciMsgType":    omciMsg.MessageType,
+		"TransCorrId":    omciMsg.TransactionID,
+		"EntityInstance": msgObj.EntityInstance,
+		"SectionNumber":  msgObj.SectionNumber,
+	}).Debug("received-download-section-request")
+
+	response := &omci.DownloadSectionResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		Result:        me.Success,
+		SectionNumber: msgObj.SectionNumber,
+	}
+
+	pkt, err := Serialize(omci.DownloadSectionResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-download-section-with-response-response")
+
+	return pkt, nil
+}
+
+func CreateEndSoftwareDownloadResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, status me.Results) ([]byte, error) {
+
+	msgObj, err := ParseEndSoftwareDownloadRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"OmciMsgType":       omciMsg.MessageType,
+		"TransCorrId":       omciMsg.TransactionID,
+		"EntityInstance":    msgObj.EntityInstance,
+		"Crc32":             msgObj.CRC32,
+		"ImageSize":         msgObj.ImageSize,
+		"NumberOfInstances": msgObj.NumberOfInstances,
+		"ImageInstances":    msgObj.ImageInstances,
+	}).Debug("received-end-software-download-request")
+
+	response := &omci.EndSoftwareDownloadResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		Result:            status,
+		NumberOfInstances: 0, // NOTE this can't be bigger than 0 this we can populate downloadResults
+		//MeResults: []omci.downloadResults{}, // FIXME downloadResults is not exported
+	}
+
+	pkt, err := Serialize(omci.EndSoftwareDownloadResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-end-software-download-response")
+
+	return pkt, nil
+}
+
+func CreateActivateSoftwareResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+	msgObj, err := ParseActivateSoftwareRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"OmciMsgType":    omciMsg.MessageType,
+		"TransCorrId":    omciMsg.TransactionID,
+		"EntityInstance": msgObj.EntityInstance,
+		"ActivateFlags":  msgObj.ActivateFlags,
+	}).Debug("received-activate-software-request")
+
+	response := &omci.ActivateSoftwareResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		Result: me.Success,
+	}
+
+	pkt, err := Serialize(omci.ActivateSoftwareResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-activate-software-response")
+
+	return pkt, nil
+}
+
+func CreateCommitSoftwareResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+	msgObj, err := ParseCommitSoftwareRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"OmciMsgType":    omciMsg.MessageType,
+		"TransCorrId":    omciMsg.TransactionID,
+		"EntityInstance": msgObj.EntityInstance,
+	}).Debug("received-commit-software-request")
+
+	response := &omci.CommitSoftwareResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+	}
+
+	pkt, err := Serialize(omci.CommitSoftwareResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-commit-software-response")
+
+	return pkt, nil
+}
+
+func ComputeDownloadSectionsCount(pkt gopacket.Packet) int {
+	msgObj, err := ParseStartSoftwareDownloadRequest(pkt)
+	if err != nil {
+		omciLogger.Error("cannot-parse-start-software-download-request")
+	}
+
+	return int(math.Ceil(float64(msgObj.ImageSize) / float64(msgObj.WindowSize)))
+}
diff --git a/internal/common/omci/image_test.go b/internal/common/omci/image_test.go
new file mode 100644
index 0000000..ad07eac
--- /dev/null
+++ b/internal/common/omci/image_test.go
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"gotest.tools/assert"
+	"testing"
+)
+
+func omciToStartSoftwareDownloadResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.StartSoftwareDownloadResponse {
+	msgLayer := (*omciPkt).Layer(omci.LayerTypeStartSoftwareDownloadResponse)
+	if msgLayer == nil {
+		t.Fatal("omci Msg layer could not be detected for StartSoftwareDownloadResponse")
+	}
+	msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
+	if !msgOk {
+		t.Fatal("omci Msg layer could not be assigned for StartSoftwareDownloadResponse")
+	}
+	return msgObj
+}
+
+func TestCreateStartSoftwareDownloadResponse(t *testing.T) {
+	omciReq := &omci.StartSoftwareDownloadRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: 1,
+		},
+		ImageSize:            32768,
+		NumberOfCircuitPacks: 1,
+		WindowSize:           31,
+		CircuitPacks:         []uint16{0},
+	}
+
+	omciReqPkt, err := Serialize(omci.StartSoftwareDownloadRequestType, omciReq, 66)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	omciReqPkt, _ = HexEncode(omciReqPkt)
+
+	// start test
+	pkt, msg, _ := ParseOpenOltOmciPacket(omciReqPkt)
+	responsePkt, err := CreateStartSoftwareDownloadResponse(pkt, msg)
+	assert.NilError(t, err)
+
+	omciResponseMsg, omciResponsePkt := omciBytesToMsg(t, responsePkt)
+	assert.Equal(t, omciResponseMsg.MessageType, omci.StartSoftwareDownloadResponseType)
+
+	getResponseLayer := omciToStartSoftwareDownloadResponse(t, omciResponsePkt)
+
+	assert.Equal(t, getResponseLayer.Result, me.Success)
+}
+
+func TestComputeDownloadSectionsCount(t *testing.T) {
+	omciReq := &omci.StartSoftwareDownloadRequest{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: 1,
+		},
+		ImageSize:            32768,
+		NumberOfCircuitPacks: 1,
+		WindowSize:           31,
+		CircuitPacks:         []uint16{0},
+	}
+
+	omciReqPkt, err := Serialize(omci.StartSoftwareDownloadRequestType, omciReq, 66)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	omciReqPkt, _ = HexEncode(omciReqPkt)
+	pkt, _, _ := ParseOpenOltOmciPacket(omciReqPkt)
+
+	count := ComputeDownloadSectionsCount(pkt)
+	assert.Equal(t, count, 1058)
+}
diff --git a/internal/common/omci/mib_test.go b/internal/common/omci/mib_test.go
index f569bce..a4ffbb7 100644
--- a/internal/common/omci/mib_test.go
+++ b/internal/common/omci/mib_test.go
@@ -60,7 +60,7 @@
 
 func createTestMibUploadNextArgs(t *testing.T, tid uint16, seqNumber uint16) mibArgs {
 	mibUploadNext, _ := CreateMibUploadNextRequest(tid, seqNumber)
-	mibUploadNext = hexDecode(mibUploadNext)
+	mibUploadNext = HexDecode(mibUploadNext)
 	mibUploadNextMsg, mibUploadNextPkt := omciBytesToMsg(t, mibUploadNext)
 
 	return mibArgs{
diff --git a/internal/common/omci/omci_base.go b/internal/common/omci/omci_base.go
index 7a9f499..c5caf41 100644
--- a/internal/common/omci/omci_base.go
+++ b/internal/common/omci/omci_base.go
@@ -29,7 +29,7 @@
 // ParseOpenOltOmciPacket receive an OMCI packet in the openolt format and returns
 // an OMCI Layer as per omci-lib-go
 func ParseOpenOltOmciPacket(pkt []byte) (gopacket.Packet, *omci.OMCI, error) {
-	rxMsg := hexDecode(pkt)
+	rxMsg := HexDecode(pkt)
 
 	// NOTE this is may not be needed, VOLTHA sends the correct message
 	if len(rxMsg) >= 44 {
@@ -63,8 +63,8 @@
 	return packet, parsed, nil
 }
 
-// hexDecode converts the hex encoding to binary
-func hexDecode(pkt []byte) []byte {
+// HexDecode converts the hex encoding to binary
+func HexDecode(pkt []byte) []byte {
 	p := make([]byte, len(pkt)/2)
 	for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
 		// Go figure this ;)
diff --git a/vendor/github.com/opencord/omci-lib-go/VERSION b/vendor/github.com/opencord/omci-lib-go/VERSION
index 9f40a87..2a0970c 100644
--- a/vendor/github.com/opencord/omci-lib-go/VERSION
+++ b/vendor/github.com/opencord/omci-lib-go/VERSION
@@ -1 +1 @@
-0.15.4
\ No newline at end of file
+0.16.1
diff --git a/vendor/github.com/opencord/omci-lib-go/mebase.go b/vendor/github.com/opencord/omci-lib-go/mebase.go
index 750233d..ec1b08c 100644
--- a/vendor/github.com/opencord/omci-lib-go/mebase.go
+++ b/vendor/github.com/opencord/omci-lib-go/mebase.go
@@ -65,11 +65,11 @@
 }
 
 // DecodeFromBytes decodes the given bytes into this layer
-func (msg *MeBasePacket) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
+func (msg *MeBasePacket) DecodeFromBytes(data []byte, p gopacket.PacketBuilder, contentSize int) error {
 	// Note: Base OMCI frame already checked for frame with at least 10 octets
 	msg.EntityClass = me.ClassID(binary.BigEndian.Uint16(data[0:]))
 	msg.EntityInstance = binary.BigEndian.Uint16(data[2:])
-	msg.BaseLayer = layers.BaseLayer{Contents: data[:4], Payload: data[4:]}
+	msg.BaseLayer = layers.BaseLayer{Contents: data[:contentSize], Payload: data[contentSize:]}
 	return nil
 }
 
diff --git a/vendor/github.com/opencord/omci-lib-go/meframe.go b/vendor/github.com/opencord/omci-lib-go/meframe.go
index 70edf4f..d53a669 100644
--- a/vendor/github.com/opencord/omci-lib-go/meframe.go
+++ b/vendor/github.com/opencord/omci-lib-go/meframe.go
@@ -286,7 +286,7 @@
 	WindowSize   uint8 // Window size - 1
 	ImageSize    uint32
 	CircuitPacks []uint16 // slot (upper 8 bits) and instance (lower 8 bits)
-	Results      []downloadResults
+	Results      []DownloadResults
 }
 
 var defaultSoftwareOptions = SoftwareOptions{
diff --git a/vendor/github.com/opencord/omci-lib-go/messagetypes.go b/vendor/github.com/opencord/omci-lib-go/messagetypes.go
index 6776b06..42a0d42 100644
--- a/vendor/github.com/opencord/omci-lib-go/messagetypes.go
+++ b/vendor/github.com/opencord/omci-lib-go/messagetypes.go
@@ -184,7 +184,7 @@
 // DecodeFromBytes decodes the given bytes of a Create Request into this layer
 func (omci *CreateRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
 	if err != nil {
 		return err
 	}
@@ -271,7 +271,7 @@
 // DecodeFromBytes decodes the given bytes of a Create Response into this layer
 func (omci *CreateResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
 	if err != nil {
 		return err
 	}
@@ -341,7 +341,7 @@
 // DecodeFromBytes decodes the given bytes of a Delete Request into this layer
 func (omci *DeleteRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
 	if err != nil {
 		return err
 	}
@@ -397,7 +397,7 @@
 // DecodeFromBytes decodes the given bytes of a Delete Response into this layer
 func (omci *DeleteResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -460,7 +460,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Request into this layer
 func (omci *SetRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -567,7 +567,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Response into this layer
 func (omci *SetResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 5)
 	if err != nil {
 		return err
 	}
@@ -636,7 +636,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Request into this layer
 func (omci *GetRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -703,7 +703,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Response into this layer
 func (omci *GetResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
 	if err != nil {
 		return err
 	}
@@ -870,7 +870,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Request into this layer
 func (omci *GetAllAlarmsRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -948,7 +948,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Response into this layer
 func (omci *GetAllAlarmsResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -1021,7 +1021,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Next Request into this layer
 func (omci *GetAllAlarmsNextRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -1097,7 +1097,7 @@
 // DecodeFromBytes decodes the given bytes of a Get All Alarms Next Response into this layer
 func (omci *GetAllAlarmsNextResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 4 + 28)
 	if err != nil {
 		return err
 	}
@@ -1173,7 +1173,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Upload Request into this layer
 func (omci *MibUploadRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
 	if err != nil {
 		return err
 	}
@@ -1240,7 +1240,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Upload Response into this layer
 func (omci *MibUploadResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -1313,7 +1313,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Upload Next Request into this layer
 func (omci *MibUploadNextRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -1386,7 +1386,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Upload Next Response into this layer
 func (omci *MibUploadNextResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 6)
 	if err != nil {
 		return err
 	}
@@ -1457,7 +1457,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Reset Request into this layer
 func (omci *MibResetRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
 	if err != nil {
 		return err
 	}
@@ -1511,7 +1511,7 @@
 // DecodeFromBytes decodes the given bytes of a MIB Reset Response into this layer
 func (omci *MibResetResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -1684,7 +1684,7 @@
 // DecodeFromBytes decodes the given bytes of an Alarm Notification into this layer
 func (omci *AlarmNotificationMsg) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 28)
 	if err != nil {
 		return err
 	}
@@ -1770,7 +1770,7 @@
 // DecodeFromBytes decodes the given bytes of an Attribute Value Change notification into this layer
 func (omci *AttributeValueChangeMsg) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -1855,7 +1855,7 @@
 // DecodeFromBytes decodes the given bytes of a Test Request into this layer
 func (omci *TestRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 5)
 	if err != nil {
 		return err
 	}
@@ -1891,7 +1891,7 @@
 // DecodeFromBytes decodes the given bytes of a Test Response into this layer
 func (omci *TestResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -1931,7 +1931,7 @@
 
 // DecodeFromBytes decodes the given bytes of a Start Software Download Request into this layer
 func (omci *StartSoftwareDownloadRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 4)
 	if err != nil {
 		return err
 	}
@@ -2007,12 +2007,12 @@
 
 /////////////////////////////////////////////////////////////////////////////
 //
-type downloadResults struct {
+type DownloadResults struct {
 	ManagedEntityID uint16 // ME ID of software image entity instance (slot number plus instance 0..1 or 2..254 vendor-specific)
 	Result          me.Results
 }
 
-func (dr *downloadResults) String() string {
+func (dr *DownloadResults) String() string {
 	return fmt.Sprintf("ME: %v (%#x), Results: %d (%v)", dr.ManagedEntityID, dr.ManagedEntityID,
 		dr.Result, dr.Result)
 }
@@ -2022,7 +2022,7 @@
 	Result            me.Results
 	WindowSize        byte // Window Size -1
 	NumberOfInstances byte
-	MeResults         []downloadResults
+	MeResults         []DownloadResults
 }
 
 func (omci *StartSoftwareDownloadResponse) String() string {
@@ -2033,7 +2033,7 @@
 // DecodeFromBytes decodes the given bytes of a Start Software Download Response into this layer
 func (omci *StartSoftwareDownloadResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
 	if err != nil {
 		return err
 	}
@@ -2065,7 +2065,7 @@
 		return errors.New(msg)
 	}
 	if omci.NumberOfInstances > 0 {
-		omci.MeResults = make([]downloadResults, omci.NumberOfInstances)
+		omci.MeResults = make([]DownloadResults, omci.NumberOfInstances)
 
 		for index := 0; index < int(omci.NumberOfInstances); index++ {
 			omci.MeResults[index].ManagedEntityID = binary.BigEndian.Uint16(data[7+(index*3):])
@@ -2155,7 +2155,7 @@
 // DecodeFromBytes decodes the given bytes of a Download Section Request into this layer
 func (omci *DownloadSectionRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -2228,7 +2228,7 @@
 // DecodeFromBytes decodes the given bytes of a Download Section Response into this layer
 func (omci *DownloadSectionResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -2313,7 +2313,7 @@
 // DecodeFromBytes decodes the given bytes of an End Software Download Request into this layer
 func (omci *EndSoftwareDownloadRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 7)
 	if err != nil {
 		return err
 	}
@@ -2395,7 +2395,7 @@
 	MeBasePacket      // Note: EntityInstance for software download is two specific values
 	Result            me.Results
 	NumberOfInstances byte
-	MeResults         []downloadResults
+	MeResults         []DownloadResults
 }
 
 func (omci *EndSoftwareDownloadResponse) String() string {
@@ -2406,7 +2406,7 @@
 // DecodeFromBytes decodes the given bytes of an End Software Download Response into this layer
 func (omci *EndSoftwareDownloadResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -2437,7 +2437,7 @@
 		return errors.New(msg)
 	}
 	if omci.NumberOfInstances > 0 {
-		omci.MeResults = make([]downloadResults, omci.NumberOfInstances)
+		omci.MeResults = make([]DownloadResults, omci.NumberOfInstances)
 
 		for index := 0; index < int(omci.NumberOfInstances); index++ {
 			omci.MeResults[index].ManagedEntityID = binary.BigEndian.Uint16(data[6+(index*3):])
@@ -2525,7 +2525,7 @@
 // DecodeFromBytes decodes the given bytes of an Activate Software Request into this layer
 func (omci *ActivateSoftwareRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -2604,7 +2604,7 @@
 // DecodeFromBytes decodes the given bytes of an Activate Softwre Response into this layer
 func (omci *ActivateSoftwareResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -2682,7 +2682,7 @@
 // DecodeFromBytes decodes the given bytes of a Commit Software Request into this layer
 func (omci *CommitSoftwareRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
 	if err != nil {
 		return err
 	}
@@ -2744,7 +2744,7 @@
 // DecodeFromBytes decodes the given bytes of a Commit Softwar Response into this layer
 func (omci *CommitSoftwareResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -2813,7 +2813,7 @@
 // DecodeFromBytes decodes the given bytes of a Synchronize Time Request into this layer
 func (omci *SynchronizeTimeRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 7)
 	if err != nil {
 		return err
 	}
@@ -2893,7 +2893,7 @@
 // DecodeFromBytes decodes the given bytes of a Synchronize Time Response into this layer
 func (omci *SynchronizeTimeResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -2981,7 +2981,7 @@
 // DecodeFromBytes decodes the given bytes of a Reboot Request into this layer
 func (omci *RebootRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -3052,7 +3052,7 @@
 // DecodeFromBytes decodes the given bytes of a Reboot Response into this layer
 func (omci *RebootResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 1)
 	if err != nil {
 		return err
 	}
@@ -3123,7 +3123,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Next Request into this layer
 func (omci *GetNextRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 4)
 	if err != nil {
 		return err
 	}
@@ -3194,7 +3194,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Next Response into this layer
 func (omci *GetNextResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
 	if err != nil {
 		return err
 	}
@@ -3312,7 +3312,7 @@
 // DecodeFromBytes decodes the given bytes of a Test Result Notification into this layer
 func (omci *TestResultMsg) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
 	if err != nil {
 		return err
 	}
@@ -3350,7 +3350,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Current Data Request into this layer
 func (omci *GetCurrentDataRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 2)
 	if err != nil {
 		return err
 	}
@@ -3416,7 +3416,7 @@
 // DecodeFromBytes decodes the given bytes of a Get Current Data Respnse into this layer
 func (omci *GetCurrentDataResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 4 + 3)
 	if err != nil {
 		return err
 	}
@@ -3503,7 +3503,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Table Request into this layer
 func (omci *SetTableRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 6 + 2)
 	if err != nil {
 		return err
 	}
@@ -3540,7 +3540,7 @@
 // DecodeFromBytes decodes the given bytes of a Set Table Response into this layer
 func (omci *SetTableResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
 	// Common ClassID/EntityID decode in msgBase
-	err := omci.MeBasePacket.DecodeFromBytes(data, p)
+	err := omci.MeBasePacket.DecodeFromBytes(data, p, 6 + 1)
 	if err != nil {
 		return err
 	}
diff --git a/vendor/github.com/opencord/omci-lib-go/omci.go b/vendor/github.com/opencord/omci-lib-go/omci.go
index 3904352..e347b48 100644
--- a/vendor/github.com/opencord/omci-lib-go/omci.go
+++ b/vendor/github.com/opencord/omci-lib-go/omci.go
@@ -113,8 +113,8 @@
 	MessageType      MessageType
 	DeviceIdentifier DeviceIdent
 	ResponseExpected bool // Significant for Download Section Request only
-	Payload          []byte
-	padding          []byte
+	Payload          []byte		// TODO: Deprecated.  Use layers.BaseLayer.Payload
+	padding          []byte		// TODO: Deprecated.  Never Used
 	Length           uint16
 	MIC              uint32
 }
@@ -137,7 +137,7 @@
 
 // LayerContents returns the OMCI specific layer information
 func (omci *OMCI) LayerContents() []byte {
-	b := make([]byte, 8)
+	b := make([]byte, 4)
 	binary.BigEndian.PutUint16(b, omci.TransactionID)
 	b[2] = byte(omci.MessageType)
 	b[3] = byte(omci.DeviceIdentifier)
@@ -252,7 +252,7 @@
 			//return errors.New(msg)
 		}
 	}
-	omci.BaseLayer = layers.BaseLayer{data[:4], data[4:]}
+	omci.BaseLayer = layers.BaseLayer{data[:4], data[4:omci.Length]}
 	p.AddLayer(omci)
 	nextLayer, err := MsgTypeToNextLayer(omci.MessageType)
 	if err != nil {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index faadcdd..93d6658 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -74,7 +74,7 @@
 github.com/opencord/cordctl/pkg/format
 # github.com/opencord/device-management-interface v0.11.0
 github.com/opencord/device-management-interface/go/dmi
-# github.com/opencord/omci-lib-go v0.15.4
+# github.com/opencord/omci-lib-go v0.16.1
 github.com/opencord/omci-lib-go
 github.com/opencord/omci-lib-go/generated
 # github.com/opencord/voltha-protos/v4 v4.0.15