VOL-4121 Image crc validation in bbsim

Change-Id: I8f53729e54db87d7d18cf09c7f2520da2f44a6ae
diff --git a/go.mod b/go.mod
index 886dd10..9529bfd 100644
--- a/go.mod
+++ b/go.mod
@@ -10,6 +10,7 @@
 
 require (
 	github.com/Shopify/sarama v1.26.1
+	github.com/boguslaw-wojcik/crc32a v1.0.0
 	github.com/golang/protobuf v1.5.2
 	github.com/google/gopacket v1.1.17
 	github.com/google/uuid v1.1.2
diff --git a/go.sum b/go.sum
index f0ba89f..6d83f93 100644
--- a/go.sum
+++ b/go.sum
@@ -5,6 +5,8 @@
 github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 h1:+JkXLHME8vLJafGhOH4aoV2Iu8bR55nU6iKMVfYVLjY=
 github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg=
 github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
+github.com/boguslaw-wojcik/crc32a v1.0.0 h1:rZUcnG4WkADJBW8tmb5ZWFN30w/mHV8+/hzM66X2ptQ=
+github.com/boguslaw-wojcik/crc32a v1.0.0/go.mod h1:BnG1x2VM7pNqIjOAHQKMu4NZ0Rn7cCxr+BmuXIbNOhM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index b112d76..11ace9f 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -18,6 +18,7 @@
 
 import (
 	"context"
+	"encoding/binary"
 	"encoding/hex"
 	"fmt"
 	"sync"
@@ -36,6 +37,7 @@
 	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
 	me "github.com/opencord/omci-lib-go/v2/generated"
 
+	"github.com/boguslaw-wojcik/crc32a"
 	"github.com/google/gopacket/layers"
 	"github.com/jpillora/backoff"
 	"github.com/looplab/fsm"
@@ -127,6 +129,7 @@
 	CommittedImageVersion         string
 	OmciResponseRate              uint8
 	OmciMsgCounter                uint8
+	ImageSectionData              []byte
 
 	// OMCI params (Used in BBR)
 	tid       uint16
@@ -980,7 +983,7 @@
 	case omci.StartSoftwareDownloadRequestType:
 
 		o.ImageSoftwareReceivedSections = 0
-
+		o.ImageSectionData = []byte{}
 		o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
 
 		if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
@@ -1015,6 +1018,7 @@
 			if o.ImageSoftwareReceivedSections == 0 {
 				o.StandbyImageVersion = string(msgObj.SectionData[0:14])
 			}
+			o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
 			o.ImageSoftwareReceivedSections++
 			if o.InternalState.Current() != OnuStateImageDownloadInProgress {
 				if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
@@ -1029,18 +1033,29 @@
 		}
 	case omci.DownloadSectionRequestWithResponseType:
 		// NOTE we only need to respond if an ACK is requested
-		responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
-		if errResp != nil {
+		if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
 			onuLogger.WithFields(log.Fields{
-				"OmciMsgType":  msg.OmciMsg.MessageType,
-				"TransCorrId":  msg.OmciMsg.TransactionID,
-				"Err":          errResp.Error(),
-				"IntfId":       o.PonPortID,
-				"SerialNumber": o.Sn(),
-			}).Error("error-while-processing-create-download-section-response")
-			return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
+				"OmciMsgType":    msg.OmciMsg.MessageType,
+				"TransCorrId":    msg.OmciMsg.TransactionID,
+				"EntityInstance": msgObj.EntityInstance,
+				"SectionNumber":  msgObj.SectionNumber,
+				"SectionData":    msgObj.SectionData,
+			}).Trace("received-download-section-request-with-response-type")
+			o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
+			responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
+
+			if errResp != nil {
+				onuLogger.WithFields(log.Fields{
+					"OmciMsgType":  msg.OmciMsg.MessageType,
+					"TransCorrId":  msg.OmciMsg.TransactionID,
+					"Err":          errResp.Error(),
+					"IntfId":       o.PonPortID,
+					"SerialNumber": o.Sn(),
+				}).Error("error-while-processing-create-download-section-response")
+				return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
+			}
+			o.ImageSoftwareReceivedSections++
 		}
-		o.ImageSoftwareReceivedSections++
 	case omci.EndSoftwareDownloadRequestType:
 
 		// In the startSoftwareDownload we get the image size and the window size.
@@ -1057,7 +1072,43 @@
 			}).Errorf("onu-did-not-receive-all-image-sections")
 			success = false
 		}
+		if success {
+			// Validate Image Crc.
+			msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
+			if err != nil {
+				onuLogger.WithFields(log.Fields{
+					"OmciMsgType":  msg.OmciMsg.MessageType,
+					"TransCorrId":  msg.OmciMsg.TransactionID,
+					"Err":          errResp.Error(),
+					"IntfId":       o.PonPortID,
+					"SerialNumber": o.Sn(),
+				}).Error("error-while-processing-end-software-download-request")
+			}
+			computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
+			//Convert the crc to network byte order
+			var byteSlice []byte = make([]byte, 4)
+			binary.LittleEndian.PutUint32(byteSlice, uint32(computedCRC))
+			computedCRC = binary.BigEndian.Uint32(byteSlice)
 
+			onuLogger.WithFields(log.Fields{
+				"OnuId":         o.ID,
+				"IntfId":        o.PonPortID,
+				"OnuSn":         o.Sn(),
+				"ReceivedCRC":   msgObj.CRC32,
+				"CalculatedCRC": computedCRC,
+			}).Debug("onu-image-crc-validation-params")
+
+			if msgObj.CRC32 != computedCRC {
+				onuLogger.WithFields(log.Fields{
+					"OnuId":         o.ID,
+					"IntfId":        o.PonPortID,
+					"OnuSn":         o.Sn(),
+					"ReceivedCRC":   msgObj.CRC32,
+					"CalculatedCRC": computedCRC,
+				}).Errorf("onu-image-crc-validation-falied")
+				success = false
+			}
+		}
 		if success {
 			if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
 				o.MibDataSync++
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/.gitignore b/vendor/github.com/boguslaw-wojcik/crc32a/.gitignore
new file mode 100644
index 0000000..a09c56d
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/.gitignore
@@ -0,0 +1 @@
+/.idea
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/LICENSE b/vendor/github.com/boguslaw-wojcik/crc32a/LICENSE
new file mode 100644
index 0000000..e24c314
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 BogusÅ‚aw Wójcik
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/README.md b/vendor/github.com/boguslaw-wojcik/crc32a/README.md
new file mode 100644
index 0000000..6b2fea8
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/README.md
@@ -0,0 +1,40 @@
+# CRC32A
+A pure Go implementation of CRC32A (ITU I.363.5) checksum missing from Golang standard library. Largely based on C implementation found in PHP source files.
+
+## Usage
+
+```go
+package main
+
+import (
+	"fmt"
+	
+	"github.com/boguslaw-wojcik/crc32a"
+)
+
+func main() {
+	b := []byte("123456789")
+	sum := crc32a.Checksum(b)
+	sumHex := crc32a.ChecksumHex(b)
+
+	fmt.Println(sum)    // 404326908
+	fmt.Println(sumHex) // 181989fc
+}
+```
+
+## Background
+There are four popular implementations of CRC32 of which three are included in Golang standard library. This package provides missing implementation of CRC32A (ITU I.363.5) popularized by bzip2 and PHP. If you're unsure what CRC32 algorithm you're using, calculate checksum for string `123456789` and compare results with the table below.
+
+| Variant | Performance | Standard Library | Data | Hex | Sum |
+| :--- | :---: | :---: | :---: | :---: | ---: |
+| **CRC32A (ITU I.363.5)** | **31.4 ns/op** | **no** | **123456789** | **181989fc** | **404326908** |
+| CRC32B (ITU V.42 / IEEE 802.3) | 24.0 ns/op | yes | 123456789 | cbf43926 | 3421780262 |
+| CRC32C (Castagnoli) | 15.2 ns/op | yes | 123456789 | e3069283 | 3808858755 |
+| CRC32K (Koopman) | 4534 ns/op | yes | 123456789 | 2d3dd0ae | 759025838 |
+
+_Note: Unless you're required to use CRC32A for legacy reasons, in general you should choose CRC32B as the most popular and widely implemented CRC32 variation._
+
+## References
+
+* [CRC32 Demystified](https://github.com/Michaelangel007/crc32) by Michael Pohoreski
+* [PHP CRC32 source](https://github.com/php/php-src/blob/php-7.3.1/ext/hash/hash_crc32.c) by PHP Group
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/crc32a.go b/vendor/github.com/boguslaw-wojcik/crc32a/crc32a.go
new file mode 100644
index 0000000..7f13216
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/crc32a.go
@@ -0,0 +1,99 @@
+package crc32a
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+)
+
+// Checksum calculates CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum.
+// This function will produce the same results as following PHP code:
+//  hexdec(hash('crc32', $data))
+func Checksum(data []byte) uint32 {
+	b := digest(data)
+
+	return binary.BigEndian.Uint32(b)
+}
+
+// ChecksumHex is a convenience function that outputs CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum as a hex string.
+// This function will produce the same results as following PHP code:
+//  hash('crc32', $data)
+func ChecksumHex(data []byte) string {
+	b := digest(data)
+
+	return hex.EncodeToString(b)
+}
+
+// digest performs checksum calculation for each byte of provided data and returns digest in form of byte array.
+func digest(data []byte) []byte {
+	var crc uint32
+	var digest = make([]byte, 4)
+
+	crc = ^crc
+	for i := 0; i < len(data); i++ {
+		crc = (crc << 8) ^ table[(crc >> 24) ^ (uint32(data[i]) & 0xff)]
+	}
+	crc = ^crc
+
+	digest[3] = byte((crc >> 24) & 0xff)
+	digest[2] = byte((crc >> 16) & 0xff)
+	digest[1] = byte((crc >> 8) & 0xff)
+	digest[0] = byte(crc & 0xff)
+
+	return digest
+}
+
+// table is the pre-generated 0x04C11DB7 polynominal used for CRC32A.
+var table = [256]uint32{
+	0x0,
+	0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+	0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
+	0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
+	0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
+	0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
+	0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
+	0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
+	0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
+	0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
+	0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+	0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
+	0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
+	0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
+	0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
+	0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
+	0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
+	0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
+	0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
+	0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+	0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
+	0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
+	0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
+	0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
+	0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
+	0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
+	0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
+	0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
+	0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+	0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
+	0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
+	0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
+	0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
+	0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
+	0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
+	0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
+	0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
+	0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+	0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
+	0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
+}
\ No newline at end of file
diff --git a/vendor/github.com/boguslaw-wojcik/crc32a/go.mod b/vendor/github.com/boguslaw-wojcik/crc32a/go.mod
new file mode 100644
index 0000000..27b7a70
--- /dev/null
+++ b/vendor/github.com/boguslaw-wojcik/crc32a/go.mod
@@ -0,0 +1 @@
+module github.com/boguslaw-wojcik/crc32a
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 1029054..056b658 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -3,6 +3,8 @@
 # github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1
 github.com/aead/cmac
 github.com/aead/cmac/aes
+# github.com/boguslaw-wojcik/crc32a v1.0.0
+github.com/boguslaw-wojcik/crc32a
 # github.com/davecgh/go-spew v1.1.1
 github.com/davecgh/go-spew/spew
 # github.com/deckarep/golang-set v1.7.1