Initial commit

Change-Id: Ie5485a0def37fc0e5a39b3fa4f22379e5e5def55
diff --git a/omci_common.go b/omci_common.go
new file mode 100644
index 0000000..d4d2e35
--- /dev/null
+++ b/omci_common.go
@@ -0,0 +1,31 @@
+/*
+ * 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 core
+
+import "fmt"
+
+type OmciError struct {
+	Msg string
+}
+
+func (e *OmciError) Error() string {
+	return fmt.Sprintf("%s", e.Msg)
+}
+
+type OnuKey struct {
+	IntfId, OnuId uint32
+}
diff --git a/omci_defs.go b/omci_defs.go
new file mode 100644
index 0000000..634d1d3
--- /dev/null
+++ b/omci_defs.go
@@ -0,0 +1,97 @@
+/*
+ * 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 core
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+
+	logger "github.com/sirupsen/logrus"
+)
+
+//
+// OMCI definitions
+//
+
+// OmciMsgType represents a OMCI message-type
+type OmciMsgType byte
+
+const (
+	// Message Types
+	_                                 = iota
+	Create                OmciMsgType = 4
+	Delete                OmciMsgType = 6
+	Set                   OmciMsgType = 8
+	Get                   OmciMsgType = 9
+	GetAllAlarms          OmciMsgType = 11
+	GetAllAlarmsNext      OmciMsgType = 12
+	MibUpload             OmciMsgType = 13
+	MibUploadNext         OmciMsgType = 14
+	MibReset              OmciMsgType = 15
+	AlarmNotification     OmciMsgType = 16
+	AttributeValueChange  OmciMsgType = 17
+	Test                  OmciMsgType = 18
+	StartSoftwareDownload OmciMsgType = 19
+	DownloadSection       OmciMsgType = 20
+	EndSoftwareDownload   OmciMsgType = 21
+	ActivateSoftware      OmciMsgType = 22
+	CommitSoftware        OmciMsgType = 23
+	SynchronizeTime       OmciMsgType = 24
+	Reboot                OmciMsgType = 25
+	GetNext               OmciMsgType = 26
+	TestResult            OmciMsgType = 27
+	GetCurrentData        OmciMsgType = 28
+	SetTable              OmciMsgType = 29 // Defined in Extended Message Set Only
+)
+
+const (
+	// Managed Entity Class values
+	GEMPortNetworkCTP OmciClass = 268
+)
+
+// OMCI Managed Entity Class
+type OmciClass uint16
+
+// OMCI Message Identifier
+type OmciMessageIdentifier struct {
+	Class    OmciClass
+	Instance uint16
+}
+
+type OmciContent [32]byte
+
+type OmciMessage struct {
+	TransactionId uint16
+	MessageType   OmciMsgType
+	DeviceId      uint8
+	MessageId     OmciMessageIdentifier
+	Content       OmciContent
+}
+
+func ParsePkt(pkt []byte) (uint16, uint8, OmciMsgType, OmciClass, uint16, OmciContent, error) {
+	var m OmciMessage
+
+	r := bytes.NewReader(pkt)
+
+	if err := binary.Read(r, binary.BigEndian, &m); err != nil {
+		logger.Error("binary.Read failed: %s", err)
+		return 0, 0, 0, 0, 0, OmciContent{}, errors.New("binary.Read failed")
+	}
+	logger.Debug("OmciRun - TransactionId: %d MessageType: %d, ME Class: %d, ME Instance: %d, Content: %x",
+		m.TransactionId, m.MessageType&0x0F, m.MessageId.Class, m.MessageId.Instance, m.Content)
+	return m.TransactionId, m.DeviceId, m.MessageType & 0x0F, m.MessageId.Class, m.MessageId.Instance, m.Content, nil
+}
diff --git a/omci_handlers.go b/omci_handlers.go
new file mode 100644
index 0000000..e7e1d68
--- /dev/null
+++ b/omci_handlers.go
@@ -0,0 +1,285 @@
+/*
+ * 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 core
+
+import (
+	"encoding/binary"
+	"errors"
+
+	logger "github.com/sirupsen/logrus"
+)
+
+type OmciMsgHandler func(class OmciClass, content OmciContent, key OnuKey) ([]byte, error)
+
+var Handlers = map[OmciMsgType]OmciMsgHandler{
+	MibReset:      mibReset,
+	MibUpload:     mibUpload,
+	MibUploadNext: mibUploadNext,
+	Set:           set,
+	Create:        create,
+	Get:           get,
+	GetAllAlarms:  getAllAlarms,
+}
+
+func mibReset(class OmciClass, content OmciContent, key OnuKey) ([]byte, error) {
+	var pkt []byte
+
+	logger.Debug("Omci MibReset")
+
+	pkt = []byte{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	return pkt, nil
+}
+
+func mibUpload(class OmciClass, content OmciContent, key OnuKey) ([]byte, error) {
+	var pkt []byte
+
+	logger.Debug("Omci MibUpload")
+
+	pkt = []byte{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+	pkt[9] = NumMibUploads // Number of subsequent MibUploadNext cmds
+
+	return pkt, nil
+}
+
+func mibUploadNext(class OmciClass, content OmciContent, key OnuKey) ([]byte, error) {
+	var pkt []byte
+
+	state := OnuOmciStateMap[key]
+
+	logger.Debug("Omci MibUploadNext %d", state.mibUploadCtr)
+
+	switch state.mibUploadCtr {
+	case 0:
+		// ONT Data (2)
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 1:
+		// Circuit Pack (6) - #1
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x01, 0xf0, 0x00, 0x2f, 0x04,
+			0x49, 0x53, 0x4b, 0x54, 0x71, 0xe8, 0x00, 0x80,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 2:
+		// Circuit Pack (6) - #2
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x01, 0x0f, 0x00, 0x42, 0x52,
+			0x43, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 3:
+		// Circuit Pack (6) - #3
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x01, 0x00, 0xf8, 0x20, 0x20,
+			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+			0x20, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 4:
+		// Circuit Pack (6) - #4
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x01, 0x00, 0x04, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 5:
+		// Circuit Pack (6) - #5
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x80, 0xf0, 0x00, 0xee, 0x01,
+			0x49, 0x53, 0x4b, 0x54, 0x71, 0xe8, 0x00, 0x80,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 6:
+		// Circuit Pack (6) - #6
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x80, 0x0f, 0x00, 0x42, 0x52,
+			0x43, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 7:
+		// Circuit Pack (6) - #7
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x80, 0x00, 0xf8, 0x20, 0x20,
+			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+			0x20, 0x20, 0x00, 0x08, 0x40, 0x10, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 8:
+		// Circuit Pack (6) - #8
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x06, 0x01, 0x80, 0x00, 0x04, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 9, 10, 11, 12:
+		// PPTP (11)
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x00, 0x0b, 0x01, 0x01, 0xff, 0xfe, 0x00, 0x2f,
+			0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0xee, 0x00,
+			0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+		pkt[11] = state.pptpInstance // ME Instance
+		state.pptpInstance++
+	case 13, 14, 15, 16, 17, 18, 19, 20:
+		// T-CONT (262)
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x01, 0x06, 0x80, 0x00, 0xe0, 0x00, 0xff, 0xff,
+			0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+		pkt[11] = state.tcontInstance // TCONT ME Instance
+		state.tcontInstance++
+	case 21:
+		// ANI-G (263)
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x01, 0x07, 0x80, 0x01, 0xff, 0xff, 0x01, 0x00,
+			0x08, 0x00, 0x30, 0x00, 0x00, 0x05, 0x09, 0x00,
+			0x00, 0xe0, 0x54, 0xff, 0xff, 0x00, 0x00, 0x0c,
+			0x63, 0x81, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+	case 22, 23, 24, 25:
+		// UNI-G (264)
+		pkt = []byte{
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+			0x01, 0x08, 0x01, 0x01, 0xf8, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+		pkt[11] = state.uniGInstance // UNI-G ME Instance
+		state.uniGInstance++
+	default:
+		logger.Error("Invalid MibUpload request %d", state.mibUploadCtr)
+		return nil, errors.New("Invalid MibUpload request")
+	}
+
+	state.mibUploadCtr++
+	return pkt, nil
+}
+
+func set(class OmciClass, content OmciContent, key OnuKey) ([]byte, error) {
+	var pkt []byte
+
+	pkt = []byte{
+		0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+	logger.Debug("Omci Set")
+
+	return pkt, nil
+}
+
+func create(class OmciClass, content OmciContent, key OnuKey) ([]byte, error) {
+	var pkt []byte
+
+	if class == GEMPortNetworkCTP {
+		if onuOmciState, ok := OnuOmciStateMap[key]; !ok {
+			logger.Error("ONU Key Error - IntfId: %d, OnuId:", key.IntfId, key.OnuId)
+			return nil, errors.New("ONU Key Error")
+		} else {
+			onuOmciState.gemPortId = binary.BigEndian.Uint16(content[:2])
+			logger.Debug("Gem Port Id %d", onuOmciState.gemPortId)
+			// FIXME
+			OnuOmciStateMap[key].state = DONE
+		}
+	}
+
+	pkt = []byte{
+		0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x01,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+	logger.Debug("Omci Create")
+
+	return pkt, nil
+}
+
+func get(class OmciClass, content OmciContent, key OnuKey) ([]byte, error) {
+	var pkt []byte
+
+	pkt = []byte{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x02, 0x01,
+		0x00, 0x20, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+	logger.Debug("Omci Get")
+
+	return pkt, nil
+}
+
+func getAllAlarms(class OmciClass, content OmciContent, key OnuKey) ([]byte, error) {
+	var pkt []byte
+
+	pkt = []byte{
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+		0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+	logger.Debug("Omci GetAllAlarms")
+
+	return pkt, nil
+}
diff --git a/omci_mib.go b/omci_mib.go
new file mode 100644
index 0000000..6fba4fd
--- /dev/null
+++ b/omci_mib.go
@@ -0,0 +1,19 @@
+/*
+ * 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 core
+
+const NumMibUploads byte = 26
diff --git a/omci_sim.go b/omci_sim.go
new file mode 100644
index 0000000..8c5a12a
--- /dev/null
+++ b/omci_sim.go
@@ -0,0 +1,54 @@
+/*
+ * 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 core
+
+import (
+	logger "github.com/sirupsen/logrus"
+)
+
+func OmciSim(intfId uint32, onuId uint32, request []byte) ([]byte, error) {
+	var resp []byte
+
+	transactionId, deviceId, msgType, class, instance, content, err := ParsePkt(request)
+	if err != nil {
+		return resp, &OmciError{"Cannot parse omci msg"}
+	}
+
+	logger.Debug("OmciRun - transactionId: %d msgType: %d, ME Class: %d, ME Instance: %d",
+		transactionId, msgType, class, instance)
+
+	key := OnuKey{intfId, onuId}
+	if _, ok := OnuOmciStateMap[key]; !ok {
+		OnuOmciStateMap[key] = NewOnuOmciState()
+	}
+
+	if _, ok := Handlers[msgType]; !ok {
+		logger.Warn("Ignore omci msg (msgType %d not handled)", msgType)
+		return resp, &OmciError{"Unimplemented omci msg"}
+	}
+
+	resp, err = Handlers[msgType](class, content, key)
+	if err != nil {
+		return resp, err
+	}
+	resp[0] = byte(transactionId >> 8)
+	resp[1] = byte(transactionId & 0xFF)
+	resp[2] = 0x2<<4 | byte(msgType)
+	resp[3] = deviceId
+
+	return resp, nil
+}
diff --git a/omci_state.go b/omci_state.go
new file mode 100644
index 0000000..5f2a314
--- /dev/null
+++ b/omci_state.go
@@ -0,0 +1,49 @@
+/*
+ * 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 core
+
+type OnuOmciState struct {
+	gemPortId     uint16
+	mibUploadCtr  uint16
+	uniGInstance  uint8
+	tcontInstance uint8
+	pptpInstance  uint8
+	state         istate
+}
+
+type istate int
+
+// TODO - Needs to reflect real ONU/OMCI state
+const (
+	INCOMPLETE istate = iota
+	DONE
+)
+
+var OnuOmciStateMap = map[OnuKey]*OnuOmciState{}
+
+func NewOnuOmciState() *OnuOmciState {
+	return &OnuOmciState{gemPortId: 0, mibUploadCtr: 0, uniGInstance: 1, tcontInstance: 0, pptpInstance: 1}
+}
+
+func GetOnuOmciState(onuId uint32, intfId uint32) istate {
+	key := OnuKey{intfId, onuId}
+	return (OnuOmciStateMap[key].state)
+}
+
+func GetGemPortId(onuId uint32, intfId uint32) uint16 {
+	key := OnuKey{intfId, onuId}
+	return (OnuOmciStateMap[key].gemPortId)
+}