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