2ce50b460b6b79c9d419c530de0b812b041a4ea0
[ric-plt/e2mgr.git] / E2Manager / converters / x2_setup_response_converter.go
1 //
2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 //  platform project (RICP).
19
20
21 package converters
22
23 // #cgo CFLAGS: -I../3rdparty/asn1codec/inc/ -I../3rdparty/asn1codec/e2ap_engine/
24 // #cgo LDFLAGS: -L ../3rdparty/asn1codec/lib/ -L../3rdparty/asn1codec/e2ap_engine/ -le2ap_codec -lasncodec
25 // #include <asn1codec_utils.h>
26 // #include <x2setup_response_wrapper.h>
27 import "C"
28 import (
29         "e2mgr/e2pdus"
30         "e2mgr/logger"
31         "fmt"
32         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
33         "github.com/pkg/errors"
34         "unsafe"
35 )
36
37 const (
38         maxnoofMBSFN                     = 8
39         maxnoofBPLMNs                    = 6
40         maxCellineNB                     = 256
41         maxnoofMBMSServiceAreaIdentities = 256
42         maxnoofBands                     = 16
43         maxPools                         = 16
44         maxnoofNeighbours                = 512
45 )
46
47 type X2SetupResponseConverter struct {
48         logger *logger.Logger
49 }
50
51 type IX2SetupResponseConverter interface {
52         UnpackX2SetupResponseAndExtract(packedBuf []byte) (*entities.GlobalNbId, *entities.Enb, error)
53 }
54
55 func NewX2SetupResponseConverter(logger *logger.Logger) *X2SetupResponseConverter {
56         return &X2SetupResponseConverter{
57                 logger: logger,
58         }
59 }
60
61 // The following are possible values of a choice field, find which the pdu contains.
62 func getENB_ID_choice(eNB_ID C.ENB_ID_t) (entities.EnbType, []byte) {
63
64         enbIdAsBitString := (*C.BIT_STRING_t)(unsafe.Pointer(&eNB_ID.choice[0]))
65         switch eNB_ID.present {
66         case C.ENB_ID_PR_macro_eNB_ID:
67                 return entities.EnbType_MACRO_ENB, C.GoBytes(unsafe.Pointer(enbIdAsBitString.buf), C.int(enbIdAsBitString.size))
68         case C.ENB_ID_PR_home_eNB_ID:
69                 return entities.EnbType_HOME_ENB, C.GoBytes(unsafe.Pointer(enbIdAsBitString.buf), C.int(enbIdAsBitString.size))
70         case C.ENB_ID_PR_short_Macro_eNB_ID:
71                 return entities.EnbType_SHORT_MACRO_ENB, C.GoBytes(unsafe.Pointer(enbIdAsBitString.buf), C.int(enbIdAsBitString.size))
72         case C.ENB_ID_PR_long_Macro_eNB_ID:
73                 return entities.EnbType_LONG_MACRO_ENB, C.GoBytes(unsafe.Pointer(enbIdAsBitString.buf), C.int(enbIdAsBitString.size))
74         }
75
76         return entities.EnbType_UNKNOWN_ENB_TYPE, nil
77 }
78
79 func getFDDInfo(fdd *C.FDD_Info_t) (*entities.FddInfo, error) {
80         var fddInfo *entities.FddInfo
81
82         if fdd != nil {
83                 fddInfo = &entities.FddInfo{UlearFcn: uint32(fdd.uL_EARFCN)}
84                 fddInfo.DlearFcn = uint32(fdd.dL_EARFCN)
85                 fddInfo.UlTransmissionBandwidth = entities.TransmissionBandwidth(1 + fdd.uL_Transmission_Bandwidth)
86                 fddInfo.DlTransmissionBandwidth = entities.TransmissionBandwidth(1 + fdd.dL_Transmission_Bandwidth)
87
88                 extIEs := (*C.ProtocolExtensionContainer_170P145_t)(unsafe.Pointer(fdd.iE_Extensions))
89                 if extIEs != nil && extIEs.list.count > 0 {
90                         count := int(extIEs.list.count)
91                         extIEs_slice := (*[1 << 30]*C.FDD_Info_ExtIEs_t)(unsafe.Pointer(extIEs.list.array))[:count:count]
92                         for _, member := range extIEs_slice {
93                                 switch member.extensionValue.present {
94                                 case C.FDD_Info_ExtIEs__extensionValue_PR_EARFCNExtension:
95                                         eARFCNExtension := (*C.EARFCNExtension_t)(unsafe.Pointer(&member.extensionValue.choice[0]))
96                                         if member.id == C.ProtocolIE_ID_id_UL_EARFCNExtension {
97                                                 fddInfo.UlearFcn = uint32(*eARFCNExtension)
98                                         }
99                                         if member.id == C.ProtocolIE_ID_id_DL_EARFCNExtension {
100                                                 fddInfo.DlearFcn = uint32(*eARFCNExtension)
101                                         }
102                                 case C.FDD_Info_ExtIEs__extensionValue_PR_OffsetOfNbiotChannelNumberToEARFCN:
103                                         /*ignored*/
104                                 case C.FDD_Info_ExtIEs__extensionValue_PR_NRS_NSSS_PowerOffset:
105                                         /*ignored*/
106                                 case C.FDD_Info_ExtIEs__extensionValue_PR_NSSS_NumOccasionDifferentPrecoder:
107                                         /*ignored*/
108                                 }
109                         }
110                 }
111         }
112
113         return fddInfo, nil
114 }
115
116 func getSpecialSubframeInfo(info C.SpecialSubframe_Info_t) *entities.SpecialSubframeInfo {
117         specialSubframeInfo := entities.SpecialSubframeInfo{}
118
119         specialSubframeInfo.SpecialSubframePatterns = entities.SpecialSubframe_Patterns(1 + info.specialSubframePatterns)
120         specialSubframeInfo.CyclicPrefixDl = entities.CyclicPrefix(1 + info.cyclicPrefixDL)
121         specialSubframeInfo.CyclicPrefixUl = entities.CyclicPrefix(1 + info.cyclicPrefixUL)
122
123         return &specialSubframeInfo
124 }
125
126 func getAdditionalSpecialSubframeInfo(info *C.AdditionalSpecialSubframe_Info_t) *entities.AdditionalSpecialSubframeInfo {
127         additionalSpecialSubframeInfo := &entities.AdditionalSpecialSubframeInfo{AdditionalSpecialSubframePatterns: entities.AdditionalSpecialSubframe_Patterns(1 + info.additionalspecialSubframePatterns)}
128
129         additionalSpecialSubframeInfo.CyclicPrefixDl = entities.CyclicPrefix(1 + info.cyclicPrefixDL)
130         additionalSpecialSubframeInfo.CyclicPrefixUl = entities.CyclicPrefix(1 + info.cyclicPrefixUL)
131
132         return additionalSpecialSubframeInfo
133 }
134
135 func getAdditionalSpecialSubframeExtensionInfo(info *C.AdditionalSpecialSubframeExtension_Info_t) *entities.AdditionalSpecialSubframeExtensionInfo {
136         additionalSpecialSubframeExtensionInfo := &entities.AdditionalSpecialSubframeExtensionInfo{AdditionalSpecialSubframePatternsExtension: entities.AdditionalSpecialSubframePatterns_Extension(1 + info.additionalspecialSubframePatternsExtension)}
137
138         additionalSpecialSubframeExtensionInfo.CyclicPrefixDl = entities.CyclicPrefix(1 + info.cyclicPrefixDL)
139         additionalSpecialSubframeExtensionInfo.CyclicPrefixUl = entities.CyclicPrefix(1 + info.cyclicPrefixUL)
140
141         return additionalSpecialSubframeExtensionInfo
142 }
143
144 func getTDDInfo(tdd *C.TDD_Info_t) (*entities.TddInfo, error) {
145         var tddInfo *entities.TddInfo
146
147         if tdd != nil {
148                 tddInfo = &entities.TddInfo{EarFcn: uint32(tdd.eARFCN)}
149                 tddInfo.TransmissionBandwidth = entities.TransmissionBandwidth(1 + tdd.transmission_Bandwidth)
150                 tddInfo.SubframeAssignment = entities.SubframeAssignment(1 + tdd.subframeAssignment)
151
152                 tddInfo.SpecialSubframeInfo = getSpecialSubframeInfo(tdd.specialSubframe_Info)
153
154                 extIEs := (*C.ProtocolExtensionContainer_170P206_t)(unsafe.Pointer(tdd.iE_Extensions))
155                 if extIEs != nil && extIEs.list.count > 0 {
156                         count := int(extIEs.list.count)
157                         extIEs_slice := (*[1 << 30]*C.TDD_Info_ExtIEs_t)(unsafe.Pointer(extIEs.list.array))[:count:count]
158                         for _, member := range extIEs_slice {
159                                 switch member.extensionValue.present {
160                                 case C.TDD_Info_ExtIEs__extensionValue_PR_AdditionalSpecialSubframe_Info:
161                                         tddInfo.AdditionalSpecialSubframeInfo = getAdditionalSpecialSubframeInfo((*C.AdditionalSpecialSubframe_Info_t)(unsafe.Pointer(&member.extensionValue.choice[0])))
162                                 case C.TDD_Info_ExtIEs__extensionValue_PR_EARFCNExtension:
163                                         tddInfo.EarFcn = uint32(*(*C.EARFCNExtension_t)(unsafe.Pointer(&member.extensionValue.choice[0])))
164                                 case C.TDD_Info_ExtIEs__extensionValue_PR_AdditionalSpecialSubframeExtension_Info:
165                                         tddInfo.AdditionalSpecialSubframeExtensionInfo = getAdditionalSpecialSubframeExtensionInfo((*C.AdditionalSpecialSubframeExtension_Info_t)(unsafe.Pointer(&member.extensionValue.choice[0])))
166                                 }
167                         }
168                 }
169         }
170
171         return tddInfo, nil
172 }
173
174 // The following are possible values of a choice field, find which the pdu contains.
175 func getSubframeAllocation_choice(subframeAllocation C.SubframeAllocation_t) (entities.SubframeAllocationType, string, error) {
176
177         switch subframeAllocation.present {
178         case C.SubframeAllocation_PR_oneframe:
179                 frameAllocation := (*C.Oneframe_t)(unsafe.Pointer(&subframeAllocation.choice[0]))
180                 return entities.SubframeAllocationType_ONE_FRAME, fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(frameAllocation.buf), C.int(frameAllocation.size))), nil
181         case C.SubframeAllocation_PR_fourframes:
182                 frameAllocation := (*C.Fourframes_t)(unsafe.Pointer(&subframeAllocation.choice[0]))
183                 return entities.SubframeAllocationType_FOUR_FRAME, fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(frameAllocation.buf), C.int(frameAllocation.size))), nil
184         }
185         return entities.SubframeAllocationType_UNKNOWN_SUBFRAME_ALLOCATION_TYPE, "", errors.Errorf("unexpected subframe allocation choice")
186 }
187
188 func getMBSFN_Subframe_Infolist(mBSFN_Subframe_Infolist *C.MBSFN_Subframe_Infolist_t) ([]*entities.MbsfnSubframe, error) {
189         var mBSFNSubframes []*entities.MbsfnSubframe
190
191         if mBSFN_Subframe_Infolist.list.count > 0 && mBSFN_Subframe_Infolist.list.count <= maxnoofMBSFN {
192                 count := int(mBSFN_Subframe_Infolist.list.count)
193                 BSFN_Subframe_Infolist_slice := (*[1 << 30]*C.MBSFN_Subframe_Info_t)(unsafe.Pointer(mBSFN_Subframe_Infolist.list.array))[:count:count]
194                 for _, member := range BSFN_Subframe_Infolist_slice {
195                         mBSFNSubframe := &entities.MbsfnSubframe{RadioframeAllocationPeriod: entities.RadioframeAllocationPeriod(1 + member.radioframeAllocationPeriod)}
196
197                         mBSFNSubframe.RadioframeAllocationOffset = uint32(member.radioframeAllocationOffset)
198
199                         allocType, subframeAllocation, err := getSubframeAllocation_choice(member.subframeAllocation)
200                         if err != nil {
201                                 return nil, err
202                         }
203                         mBSFNSubframe.SubframeAllocation = subframeAllocation
204                         mBSFNSubframe.SubframeAllocationType = allocType
205
206                         mBSFNSubframes = append(mBSFNSubframes, mBSFNSubframe)
207                 }
208         }
209
210         return mBSFNSubframes, nil
211 }
212
213 func getPRACHConfiguration(prachConf *C.PRACH_Configuration_t) *entities.PrachConfiguration {
214
215         var prachConfiguration *entities.PrachConfiguration
216
217         prachConfiguration = &entities.PrachConfiguration{RootSequenceIndex: uint32(prachConf.rootSequenceIndex)}
218         prachConfiguration.ZeroCorrelationZoneConfiguration = uint32(prachConf.zeroCorrelationIndex)
219         prachConfiguration.HighSpeedFlag = prachConf.highSpeedFlag != 0
220         prachConfiguration.PrachFrequencyOffset = uint32(prachConf.prach_FreqOffset)
221         if prachConf.prach_ConfigIndex != nil {
222                 prachConfiguration.PrachConfigurationIndex = uint32(*prachConf.prach_ConfigIndex)
223         }
224
225         return prachConfiguration
226 }
227 func getServedCellsInfoExt(extIEs *C.ProtocolExtensionContainer_170P192_t, servedCellInfo *entities.ServedCellInfo) error {
228
229         if extIEs != nil && extIEs.list.count > 0 {
230                 count := int(extIEs.list.count)
231                 extIEs_slice := (*[1 << 30]*C.ServedCell_Information_ExtIEs_t)(unsafe.Pointer(extIEs.list.array))[:count:count]
232                 for _, member := range extIEs_slice {
233                         switch member.extensionValue.present {
234                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_Number_of_Antennaports:
235                                 ports := (*C.Number_of_Antennaports_t)(unsafe.Pointer(&member.extensionValue.choice[0]))
236                                 servedCellInfo.NumberOfAntennaPorts = entities.NumberOfAntennaPorts(1 + *ports)
237                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_PRACH_Configuration:
238                                 prachConfiguration := getPRACHConfiguration((*C.PRACH_Configuration_t)(unsafe.Pointer(&member.extensionValue.choice[0])))
239                                 servedCellInfo.PrachConfiguration = prachConfiguration
240                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_MBSFN_Subframe_Infolist:
241                                 mBSFN_Subframe_Infolist, err := getMBSFN_Subframe_Infolist((*C.MBSFN_Subframe_Infolist_t)(unsafe.Pointer(&member.extensionValue.choice[0])))
242                                 if err != nil {
243                                         return err
244                                 }
245                                 servedCellInfo.MbsfnSubframeInfos = mBSFN_Subframe_Infolist
246                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_CSG_Id:
247                                 csgId := (*C.CSG_Id_t)(unsafe.Pointer(&member.extensionValue.choice[0]))
248                                 servedCellInfo.CsgId = fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(csgId.buf), C.int(csgId.size)))
249                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_MBMS_Service_Area_Identity_List:
250                                 mBMS_Service_Area_Identity_List := (*C.MBMS_Service_Area_Identity_List_t)(unsafe.Pointer(&member.extensionValue.choice[0]))
251                                 if mBMS_Service_Area_Identity_List.list.count > 0 && mBMS_Service_Area_Identity_List.list.count < maxnoofMBMSServiceAreaIdentities {
252                                         count := int(mBMS_Service_Area_Identity_List.list.count)
253                                         mBMS_Service_Area_Identity_List_slice := (*[1 << 30]*C.MBMS_Service_Area_Identity_t)(unsafe.Pointer(mBMS_Service_Area_Identity_List.list.array))[:count:count]
254                                         for _, identity := range mBMS_Service_Area_Identity_List_slice {
255                                                 servedCellInfo.MbmsServiceAreaIdentities = append(servedCellInfo.MbmsServiceAreaIdentities, fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(identity.buf), C.int(identity.size))))
256                                         }
257                                 }
258                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_MultibandInfoList:
259                                 multibandInfoList := (*C.MultibandInfoList_t)(unsafe.Pointer(&member.extensionValue.choice[0]))
260                                 if multibandInfoList.list.count > 0 && multibandInfoList.list.count < maxnoofBands {
261                                         count := int(multibandInfoList.list.count)
262                                         multibandInfoList_slice := (*[1 << 30]*C.BandInfo_t)(unsafe.Pointer(multibandInfoList.list.array))[:count:count]
263                                         for _, bandInfo := range multibandInfoList_slice {
264                                                 servedCellInfo.MultibandInfos = append(servedCellInfo.MultibandInfos, uint32(bandInfo.freqBandIndicator))
265                                         }
266                                 }
267                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_FreqBandIndicatorPriority:
268                                 priority := (*C.FreqBandIndicatorPriority_t)(unsafe.Pointer(&member.extensionValue.choice[0]))
269                                 servedCellInfo.FreqBandIndicatorPriority = entities.FreqBandIndicatorPriority(1 + *priority)
270                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_BandwidthReducedSI:
271                                 si := (*C.BandwidthReducedSI_t)(unsafe.Pointer(&member.extensionValue.choice[0]))
272                                 servedCellInfo.BandwidthReducedSi = entities.BandwidthReducedSI(1 + *si)
273                         case C.ServedCell_Information_ExtIEs__extensionValue_PR_ProtectedEUTRAResourceIndication:
274                                 /*ignored*/
275
276                         }
277
278                 }
279
280         }
281
282         return nil
283 }
284
285 func getServedCellsNeighbour_Info(neighbour_Information *C.Neighbour_Information_t) ([]*entities.NeighbourInformation, error) {
286         var neighbours []*entities.NeighbourInformation
287
288         if neighbour_Information != nil && neighbour_Information.list.count > 0 && neighbour_Information.list.count <= maxnoofNeighbours {
289                 count := int(neighbour_Information.list.count)
290                 neighbour_Information_slice := (*[1 << 30]*C.Neighbour_Information__Member)(unsafe.Pointer(neighbour_Information.list.array))[:count:count]
291                 for _, member := range neighbour_Information_slice {
292
293                         //pLMN_Identity:eUTRANcellIdentifier
294                         plmnId := C.GoBytes(unsafe.Pointer(member.eCGI.pLMN_Identity.buf), C.int(member.eCGI.pLMN_Identity.size))
295                         eUTRANcellIdentifier := C.GoBytes(unsafe.Pointer(member.eCGI.eUTRANcellIdentifier.buf), C.int(member.eCGI.eUTRANcellIdentifier.size))
296                         neighbourInfo := &entities.NeighbourInformation{Ecgi: fmt.Sprintf("%02x:%02x", plmnId, eUTRANcellIdentifier)}
297
298                         neighbourInfo.Pci = uint32(member.pCI)
299
300                         neighbourInfo.EarFcn = uint32(member.eARFCN)
301
302                         extIEs := (*C.ProtocolExtensionContainer_170P172_t)(unsafe.Pointer(member.iE_Extensions))
303                         if extIEs != nil && extIEs.list.count > 0 {
304                                 count := int(extIEs.list.count)
305                                 neighbour_Information_ExtIEs_slice := (*[1 << 30]*C.Neighbour_Information_ExtIEs_t)(unsafe.Pointer(extIEs.list.array))[:count:count]
306                                 for _, neighbour_Information_ExtIE := range neighbour_Information_ExtIEs_slice {
307                                         switch neighbour_Information_ExtIE.extensionValue.present {
308                                         case C.Neighbour_Information_ExtIEs__extensionValue_PR_TAC:
309                                                 tac := (*C.TAC_t)(unsafe.Pointer(&neighbour_Information_ExtIE.extensionValue.choice[0]))
310                                                 neighbourInfo.Tac = fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(tac.buf), C.int(tac.size)))
311                                         case C.Neighbour_Information_ExtIEs__extensionValue_PR_EARFCNExtension:
312                                                 earFcn := (*C.EARFCNExtension_t)(unsafe.Pointer(&neighbour_Information_ExtIE.extensionValue.choice[0]))
313                                                 neighbourInfo.EarFcn = uint32(*earFcn)
314                                         }
315                                 }
316                         }
317
318                         neighbours = append(neighbours, neighbourInfo)
319                 }
320         }
321
322         return neighbours, nil
323 }
324
325 func getServedCells(servedCellsIE *C.ServedCells_t) ([]*entities.ServedCellInfo, error) {
326         var servedCells []*entities.ServedCellInfo
327
328         if servedCellsIE != nil && servedCellsIE.list.count > 0 && servedCellsIE.list.count < maxCellineNB {
329                 count := int(servedCellsIE.list.count)
330                 servedCells__Member_slice := (*[1 << 30]*C.ServedCells__Member)(unsafe.Pointer(servedCellsIE.list.array))[:count:count]
331                 for _, member := range servedCells__Member_slice {
332                         servedCellInfo := &entities.ServedCellInfo{Pci: uint32(member.servedCellInfo.pCI)}
333
334                         //pLMN_Identity:eUTRANcellIdentifier
335                         plmnId := C.GoBytes(unsafe.Pointer(member.servedCellInfo.cellId.pLMN_Identity.buf), C.int(member.servedCellInfo.cellId.pLMN_Identity.size))
336                         eUTRANcellIdentifier := C.GoBytes(unsafe.Pointer(member.servedCellInfo.cellId.eUTRANcellIdentifier.buf), C.int(member.servedCellInfo.cellId.eUTRANcellIdentifier.size))
337                         servedCellInfo.CellId = fmt.Sprintf("%02x:%02x", plmnId, eUTRANcellIdentifier)
338
339                         servedCellInfo.Tac = fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(member.servedCellInfo.tAC.buf), C.int(member.servedCellInfo.tAC.size)))
340
341                         if member.servedCellInfo.broadcastPLMNs.list.count > 0 && member.servedCellInfo.broadcastPLMNs.list.count <= maxnoofBPLMNs {
342                                 count := int(member.servedCellInfo.broadcastPLMNs.list.count)
343                                 pLMN_Identity_slice := (*[1 << 30]*C.PLMN_Identity_t)(unsafe.Pointer(member.servedCellInfo.broadcastPLMNs.list.array))[:count:count]
344                                 for _, pLMN_Identity := range pLMN_Identity_slice {
345                                         servedCellInfo.BroadcastPlmns = append(servedCellInfo.BroadcastPlmns, fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(pLMN_Identity.buf), C.int(pLMN_Identity.size))))
346                                 }
347                         }
348
349                         switch member.servedCellInfo.eUTRA_Mode_Info.present {
350                         case C.EUTRA_Mode_Info_PR_fDD:
351                                 if fdd, err := getFDDInfo(*(**C.FDD_Info_t)(unsafe.Pointer(&member.servedCellInfo.eUTRA_Mode_Info.choice[0]))); fdd != nil && err == nil {
352                                         servedCellInfo.ChoiceEutraMode, servedCellInfo.EutraMode = &entities.ChoiceEUTRAMode{Fdd: fdd}, entities.Eutra_FDD
353                                 } else {
354                                         return nil, err
355                                 }
356                         case C.EUTRA_Mode_Info_PR_tDD:
357                                 if tdd, err := getTDDInfo(*(**C.TDD_Info_t)(unsafe.Pointer(&member.servedCellInfo.eUTRA_Mode_Info.choice[0]))); tdd != nil && err == nil {
358                                         servedCellInfo.ChoiceEutraMode, servedCellInfo.EutraMode = &entities.ChoiceEUTRAMode{Tdd: tdd}, entities.Eutra_TDD
359                                 } else {
360                                         return nil, err
361                                 }
362                         }
363
364                         neighbours, err := getServedCellsNeighbour_Info(member.neighbour_Info)
365                         if err != nil {
366                                 return nil, err
367                         }
368                         servedCellInfo.NeighbourInfos = neighbours
369
370                         if err := getServedCellsInfoExt((*C.ProtocolExtensionContainer_170P192_t)(unsafe.Pointer(member.servedCellInfo.iE_Extensions)), servedCellInfo); err != nil {
371                                 return nil, err
372                         }
373
374                         servedCells = append(servedCells, servedCellInfo)
375
376                 }
377         }
378
379         return servedCells, nil
380 }
381
382 func getGUGroupIDList(guGroupIDList *C.GUGroupIDList_t) []string {
383         var ids []string
384
385         if guGroupIDList != nil && guGroupIDList.list.count > 0 && guGroupIDList.list.count <= maxPools {
386                 count := int(guGroupIDList.list.count)
387                 guGroupIDList_slice := (*[1 << 30]*C.GU_Group_ID_t)(unsafe.Pointer(guGroupIDList.list.array))[:count:count]
388                 for _, guGroupID := range guGroupIDList_slice {
389                         plmnId := C.GoBytes(unsafe.Pointer(guGroupID.pLMN_Identity.buf), C.int(guGroupID.pLMN_Identity.size))
390                         mME_Group_ID := C.GoBytes(unsafe.Pointer(guGroupID.mME_Group_ID.buf), C.int(guGroupID.mME_Group_ID.size))
391                         ids = append(ids, fmt.Sprintf("%02x:%02x", plmnId, mME_Group_ID))
392                 }
393         }
394
395         return ids
396 }
397
398 // Populate  the ENB structure with data from the pdu
399 // Return the ENB and the associated key which can later be used to retrieve the ENB from the database.
400 func x2SetupResponseToProtobuf(pdu *C.E2AP_PDU_t) (*entities.GlobalNbId, *entities.Enb, error) {
401         var globalNbId *entities.GlobalNbId
402
403         enb := entities.Enb{}
404
405         if pdu.present == C.E2AP_PDU_PR_successfulOutcome {
406                 //dereference a union of pointers (C union is represented as a byte array with the size of the largest member)
407                 successfulOutcome := *(**C.SuccessfulOutcome_t)(unsafe.Pointer(&pdu.choice[0]))
408                 if successfulOutcome != nil && successfulOutcome.value.present == C.SuccessfulOutcome__value_PR_X2SetupResponse {
409                         x2SetupResponse := (*C.X2SetupResponse_t)(unsafe.Pointer(&successfulOutcome.value.choice[0]))
410                         if x2SetupResponse != nil && x2SetupResponse.protocolIEs.list.count > 0 {
411                                 count := int(x2SetupResponse.protocolIEs.list.count)
412                                 x2SetupResponse_IEs_slice := (*[1 << 30]*C.X2SetupResponse_IEs_t)(unsafe.Pointer(x2SetupResponse.protocolIEs.list.array))[:count:count]
413                                 for _, x2SetupResponse_IE := range x2SetupResponse_IEs_slice {
414                                         switch x2SetupResponse_IE.value.present {
415                                         case C.X2SetupResponse_IEs__value_PR_GlobalENB_ID:
416                                                 globalENB_ID := (*C.GlobalENB_ID_t)(unsafe.Pointer(&x2SetupResponse_IE.value.choice[0]))
417                                                 plmnId := C.GoBytes(unsafe.Pointer(globalENB_ID.pLMN_Identity.buf), C.int(globalENB_ID.pLMN_Identity.size))
418                                                 enbType, enbVal := getENB_ID_choice(globalENB_ID.eNB_ID)
419
420                                                 globalNbId = &entities.GlobalNbId{}
421                                                 globalNbId.NbId = fmt.Sprintf("%02x", enbVal)
422                                                 globalNbId.PlmnId = fmt.Sprintf("%02x", plmnId)
423                                                 enb.EnbType = enbType
424
425                                         case C.X2SetupResponse_IEs__value_PR_ServedCells:
426                                                 ServedCells, err := getServedCells((*C.ServedCells_t)(unsafe.Pointer(&x2SetupResponse_IE.value.choice[0])))
427                                                 if err != nil {
428                                                         return globalNbId, nil, err
429                                                 }
430                                                 enb.ServedCells = ServedCells
431                                         case C.X2SetupResponse_IEs__value_PR_GUGroupIDList:
432                                                 enb.GuGroupIds = getGUGroupIDList((*C.GUGroupIDList_t)(unsafe.Pointer(&x2SetupResponse_IE.value.choice[0])))
433                                         case C.X2SetupResponse_IEs__value_PR_CriticalityDiagnostics:
434                                                 /*ignored*/
435                                         case C.X2SetupResponse_IEs__value_PR_LHN_ID:
436                                                 /*ignored*/
437                                         }
438                                 }
439                         }
440                 }
441         }
442
443         return globalNbId, &enb, nil
444 }
445
446 func (c *X2SetupResponseConverter) UnpackX2SetupResponseAndExtract(packedBuf []byte) (*entities.GlobalNbId, *entities.Enb, error) {
447         pdu, err := UnpackX2apPdu(c.logger, e2pdus.MaxAsn1CodecAllocationBufferSize, len(packedBuf), packedBuf, e2pdus.MaxAsn1CodecMessageBufferSize)
448         if err != nil {
449                 return nil, nil, err
450         }
451
452         defer C.delete_pdu(pdu)
453         return x2SetupResponseToProtobuf(pdu)
454 }