E2AP Abstraction Changes
[ric-app/hw.git] / src / xapp-formats / e2sm / e2sm.cc
1 /*
2   ==================================================================================
3
4   Copyright (c) 2018-2019 AT&T Intellectual Property.
5   
6   Licensed under the Apache License, Version 2.0 (the "License");
7   you may not use this file except in compliance with the License.
8   You may obtain a copy of the License at
9   
10   http://www.apache.org/licenses/LICENSE-2.0
11   
12   Unless required by applicable law or agreed to in writing, softwares
13   distributed under the License is distributed on an "AS IS" BASIS,
14   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   See the License for the specific language governing permissions and
16   limitations under the License.
17   ==================================================================================
18 */
19
20 /* Classes to handle E2 service model based on e2sm-gNB-X2-release-1-v040.asn */
21
22 #include "e2sm.hpp"
23
24
25
26   //initialize
27   e2sm_event_trigger::e2sm_event_trigger(void){
28
29     memset(&gNodeB_ID, 0, sizeof(E2N_GlobalGNB_ID_t));
30
31     event_trigger = 0;
32     event_trigger = ( E2N_E2SM_gNB_X2_eventTriggerDefinition_t *)calloc(1, sizeof( E2N_E2SM_gNB_X2_eventTriggerDefinition_t));
33     assert(event_trigger != 0);
34     
35     // allocate space for gNodeB id  (used for encoding)
36     gNodeB_ID.gNB_ID.choice.gNB_ID.buf = 0;
37     gNodeB_ID.gNB_ID.choice.gNB_ID.buf = (uint8_t *)calloc(4, sizeof(uint8_t));
38     assert(gNodeB_ID.gNB_ID.choice.gNB_ID.buf != 0);
39     
40     // allocate space for plmn identity  (used for encoding)
41     gNodeB_ID.pLMN_Identity.buf = 0;
42     gNodeB_ID.pLMN_Identity.buf = (uint8_t *) calloc(4, sizeof(uint8_t));
43     assert(gNodeB_ID.pLMN_Identity.buf != 0);
44
45     ie_list = 0;
46     ie_list = ( struct E2N_InterfaceProtocolIE_Item *) calloc(INITIAL_LIST_SIZE, sizeof( struct E2N_InterfaceProtocolIE_Item));
47     assert(ie_list != 0);
48     ie_list_size = INITIAL_LIST_SIZE;
49
50     condition_list = 0;
51     condition_list = (E2N_E2SM_gNB_X2_eventTriggerDefinition::E2N_E2SM_gNB_X2_eventTriggerDefinition__interfaceProtocolIE_List *) calloc(1, sizeof(E2N_E2SM_gNB_X2_eventTriggerDefinition::E2N_E2SM_gNB_X2_eventTriggerDefinition__interfaceProtocolIE_List ));
52     assert(condition_list != 0);
53
54  
55     
56   };
57   
58 e2sm_event_trigger::~e2sm_event_trigger(void){
59
60   mdclog_write(MDCLOG_DEBUG, "Freeing event trigger object memory");
61   for(int i = 0; i < condition_list->list.size; i++){
62     condition_list->list.array[i] = 0;
63   }
64
65   if (condition_list->list.size > 0){
66     free(condition_list->list.array);
67     condition_list->list.array = 0;
68     condition_list->list.size = 0;
69     condition_list->list.count = 0;
70   }
71
72   free(condition_list);
73   condition_list = 0;
74   
75   free(gNodeB_ID.gNB_ID.choice.gNB_ID.buf);
76   gNodeB_ID.gNB_ID.choice.gNB_ID.buf = 0;
77   
78   free(gNodeB_ID.pLMN_Identity.buf);
79   gNodeB_ID.pLMN_Identity.buf = 0;
80   
81   free(ie_list);
82   ie_list = 0;
83   
84   event_trigger->interface_ID.choice.global_gNB_ID = 0;
85   event_trigger->interfaceProtocolIE_List = 0;
86   
87   ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger);
88   mdclog_write(MDCLOG_DEBUG, "Freed event trigger object memory");
89
90  
91 };
92
93 bool e2sm_event_trigger::encode_event_trigger(unsigned char *buf, size_t *size, e2sm_event_trigger_helper &helper){
94   
95   bool res;
96   res = set_fields(event_trigger, helper);
97   if (!res){
98     return false;
99   }
100   
101   int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger, errbuf, &errbuf_len);
102   if(ret_constr){
103     error_string.assign(&errbuf[0], errbuf_len);
104     return false;
105   }
106
107   //xer_fprint(stdout, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger);
108   
109   asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger, buf, *size);
110   
111   if(retval.encoded == -1){
112     error_string.assign(strerror(errno));
113     return false;
114   }
115   else if (retval.encoded > *size){
116     std::stringstream ss;
117     ss  <<"Error encoding event trigger definition. Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
118     error_string = ss.str();
119     return false;
120   }
121   else{
122     *size = retval.encoded;
123   }
124   
125   return true;
126 }
127
128
129 bool e2sm_event_trigger::set_fields(E2N_E2SM_gNB_X2_eventTriggerDefinition_t * ref_event_trigger, e2sm_event_trigger_helper & helper){
130   if(ref_event_trigger == 0){
131     error_string = "Invalid reference for Event Trigger Definition set fields";
132     return false;
133   }
134       
135   // set the message type
136   ref_event_trigger->interfaceMessageType.procedureCode = helper.procedure_code;
137   ref_event_trigger->interfaceMessageType.typeOfMessage = helper.message_type;
138   
139   ref_event_trigger->interfaceDirection = helper.interface_direction; 
140   ref_event_trigger->interface_ID.present = E2N_Interface_ID_PR_global_gNB_ID;
141   
142   ref_event_trigger->interface_ID.choice.global_gNB_ID = &gNodeB_ID;
143
144   // to do : need to put correct code here for upding plmn id and gNodeB
145   // for now just place holders :
146   //================================================================
147   memcpy(gNodeB_ID.pLMN_Identity.buf, helper.plmn_id.c_str(), 3);
148   gNodeB_ID.pLMN_Identity.size = 3;
149   
150   memcpy(gNodeB_ID.gNB_ID.choice.gNB_ID.buf, helper.egNB_id.c_str(), 3);
151   gNodeB_ID.gNB_ID.choice.gNB_ID.size = 3;
152   
153   // we only do global gNodeB id for now, not eNodeB
154   gNodeB_ID.gNB_ID.present = E2N_GNB_ID_PR_gNB_ID;
155   //================================================================
156   
157   
158   // Add in any requested IE items
159   std::vector<Item> * ref_ie_array = helper.get_list();
160
161   if (ref_ie_array->size() == 0){
162     ref_event_trigger->interfaceProtocolIE_List = 0;
163     
164   }
165   else{
166     ref_event_trigger->interfaceProtocolIE_List = condition_list;
167     
168     //resize memory ? 
169     if(ref_ie_array->size() > ie_list_size){
170       ie_list_size = 2 * ref_ie_array->size();
171       free(ie_list);
172       ie_list = (struct E2N_InterfaceProtocolIE_Item *)calloc(ie_list_size, sizeof(struct E2N_InterfaceProtocolIE_Item));
173       assert(ie_list != 0);
174     }
175     
176     // reset the count so that adds start from the beginning
177     ref_event_trigger->interfaceProtocolIE_List->list.count = 0;
178     
179     for(unsigned int i = 0; i < ref_ie_array->size(); i++){
180
181       ie_list[i].interfaceProtocolIE_ID = (*ref_ie_array)[i].interface_id;
182       ie_list[i].interfaceProtocolIE_Test = (*ref_ie_array)[i].test;
183       
184       //switch(ie_list[i].interfaceProtocolIE_Value.present){
185       switch((*ref_ie_array)[i].val_type){
186         
187       case (E2N_InterfaceProtocolIE_Value_PR_valueInt):
188         ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueInt;
189         ie_list[i].interfaceProtocolIE_Value.choice.valueInt = (*ref_ie_array)[i].value_n;
190         break;
191         
192       case (E2N_InterfaceProtocolIE_Value_PR_valueEnum):
193         ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueEnum;
194         ie_list[i].interfaceProtocolIE_Value.choice.valueEnum = (*ref_ie_array)[i].value_n;
195         break;
196         
197       case (E2N_InterfaceProtocolIE_Value_PR_valueBool):
198         ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueBool;
199         ie_list[i].interfaceProtocolIE_Value.choice.valueBool = (*ref_ie_array)[i].value_n;
200         break;
201         
202       case (E2N_InterfaceProtocolIE_Value_PR_valueBitS):
203         ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueBitS;
204         ie_list[i].interfaceProtocolIE_Value.choice.valueBitS.buf = (uint8_t *)(*ref_ie_array)[i].value_s.c_str();
205         ie_list[i].interfaceProtocolIE_Value.choice.valueBitS.size = (*ref_ie_array)[i].value_s.length();
206         break;
207
208       case (E2N_InterfaceProtocolIE_Value_PR_valueOctS):
209         ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueOctS;
210         ie_list[i].interfaceProtocolIE_Value.choice.valueOctS.buf = (uint8_t *)(*ref_ie_array)[i].value_s.c_str();
211         ie_list[i].interfaceProtocolIE_Value.choice.valueOctS.size = (*ref_ie_array)[i].value_s.length();
212         break;
213
214       default:
215         {
216           std::stringstream ss;
217           ss <<"Error ! " << __FILE__ << "," << __LINE__ << " illegal enum " << (*ref_ie_array)[i].val_type << " for interface Protocol IE value" << std::endl;
218           std::string error_string = ss.str();
219           return false;
220         }
221       }
222       
223       ASN_SEQUENCE_ADD(ref_event_trigger->interfaceProtocolIE_List, &ie_list[i]);
224     }
225   }
226
227   return true;
228 };
229   
230
231 bool e2sm_event_trigger::get_fields(E2N_E2SM_gNB_X2_eventTriggerDefinition_t * ref_event_trigger, e2sm_event_trigger_helper & helper){
232
233   if (ref_event_trigger == 0){
234     error_string = "Invalid reference for Event Trigger definition get fields";
235     return false;
236   }
237   
238   helper.procedure_code = ref_event_trigger->interfaceMessageType.procedureCode;
239   helper.message_type   = ref_event_trigger->interfaceMessageType.typeOfMessage;
240   helper.interface_direction = ref_event_trigger->interfaceDirection;
241   
242   helper.plmn_id.assign((const char *)ref_event_trigger->interface_ID.choice.global_gNB_ID->pLMN_Identity.buf, ref_event_trigger->interface_ID.choice.global_gNB_ID->pLMN_Identity.size);
243   helper.egNB_id.assign((const char *)ref_event_trigger->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.buf, ref_event_trigger->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.size);
244   for(int i = 0; i < ref_event_trigger->interfaceProtocolIE_List->list.count; i++){
245     struct E2N_InterfaceProtocolIE_Item * ie_item = ref_event_trigger->interfaceProtocolIE_List->list.array[i];
246     switch(ie_item->interfaceProtocolIE_Value.present){
247     case (E2N_InterfaceProtocolIE_Value_PR_valueInt):
248       helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, ie_item->interfaceProtocolIE_Value.choice.valueInt);
249       break;
250     case (E2N_InterfaceProtocolIE_Value_PR_valueEnum):
251       helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, ie_item->interfaceProtocolIE_Value.choice.valueEnum);
252       break;
253     case (E2N_InterfaceProtocolIE_Value_PR_valueBool):
254       helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, ie_item->interfaceProtocolIE_Value.choice.valueBool);     
255       break;
256     case (E2N_InterfaceProtocolIE_Value_PR_valueBitS):
257       helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, std::string((const char *)ie_item->interfaceProtocolIE_Value.choice.valueBitS.buf,ie_item->interfaceProtocolIE_Value.choice.valueBitS.size) );
258       break;
259     case (E2N_InterfaceProtocolIE_Value_PR_valueOctS):
260       helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, std::string((const char *)ie_item->interfaceProtocolIE_Value.choice.valueOctS.buf,ie_item->interfaceProtocolIE_Value.choice.valueOctS.size) );
261       break;
262     default:
263       mdclog_write(MDCLOG_ERR, "Error : %s, %d: Unkown interface protocol IE type %d in event trigger definition\n", __FILE__, __LINE__, ie_item->interfaceProtocolIE_Value.present);
264       return false;
265     }
266   }
267   
268   return true;
269 };
270     
271
272   
273    
274 // initialize
275 e2sm_indication::e2sm_indication(void) {
276   
277   memset(&gNodeB_ID, 0, sizeof(E2N_GlobalGNB_ID_t));
278     
279   // allocate space for gNodeB id  (used for encoding)
280   gNodeB_ID.gNB_ID.choice.gNB_ID.buf = (uint8_t *)calloc(4, sizeof(uint8_t));
281   assert(gNodeB_ID.gNB_ID.choice.gNB_ID.buf != 0);
282     
283   // allocate space for plmn identity  (used for encoding)
284   gNodeB_ID.pLMN_Identity.buf = (uint8_t *) calloc(4, sizeof(uint8_t));
285   assert(gNodeB_ID.pLMN_Identity.buf != 0);
286
287   header = 0;
288   header = (E2N_E2SM_gNB_X2_indicationHeader_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_indicationHeader_t));
289   assert(header != 0);
290
291   message = 0;
292   message = (E2N_E2SM_gNB_X2_indicationMessage_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_indicationMessage_t));
293   assert(message != 0);
294 }
295   
296 e2sm_indication::~e2sm_indication(void){
297   mdclog_write(MDCLOG_DEBUG, "Freeing E2N_E2SM Indication  object memory");
298
299   free(gNodeB_ID.gNB_ID.choice.gNB_ID.buf);
300   free(gNodeB_ID.pLMN_Identity.buf);
301   
302   header->interface_ID.choice.global_gNB_ID = 0;
303
304   ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_indicationHeader, header);
305
306   message->interfaceMessage.buf = 0;
307   message->interfaceMessage.size = 0;
308
309   ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_indicationMessage, message);
310   mdclog_write(MDCLOG_DEBUG, "Freed E2SM Indication  object memory");
311     
312 }
313   
314   
315
316 bool e2sm_indication::encode_indication_header(unsigned char *buf, size_t *size, e2sm_header_helper &helper){
317     
318   bool res;
319   res = set_header_fields(header, helper);
320   if (!res){
321     return false;
322   }
323
324   int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_indicationHeader, header, errbuf, &errbuf_len);
325   if(ret_constr){
326     error_string.assign(&errbuf[0], errbuf_len);
327     error_string = "E2SM Indication Header Constraint failed : " + error_string;
328
329     return false;
330   }
331
332   asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_indicationHeader, header, buf, *size);
333
334   if(retval.encoded == -1){
335     error_string.assign(strerror(errno));
336     error_string = "Error encoding E2N_E2SM Indication Header. Reason = " + error_string;
337     return false;
338   }
339   else if (retval.encoded > *size){
340     std::stringstream ss;
341     ss  <<"Error encoding E2SM Indication Header . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
342     error_string = ss.str();
343     return false;
344   }
345   else{
346     *size = retval.encoded;
347   }
348     
349   return true;
350 }
351
352
353 bool e2sm_indication::encode_indication_message(unsigned char *buf, size_t *size, e2sm_message_helper &helper){
354
355   set_message_fields(message, helper); 
356
357   int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_indicationMessage, message, errbuf, &errbuf_len);
358   if(ret_constr){
359     error_string.assign(&errbuf[0], errbuf_len);
360     error_string = "E2SM Indication Message Constraint failed : " + error_string;
361     return false;
362   }
363
364   asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_indicationMessage, message, buf, *size);
365   if(retval.encoded == -1){
366     error_string.assign(strerror(errno));
367     error_string = "Error encoding E2SM Indication Header. Reason = " + error_string;
368     return false;
369   }
370   else if (retval.encoded > *size){
371     std::stringstream ss;
372     ss  <<"Error encoding E2N_E2SM Indication Message . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
373     error_string = ss.str();
374     
375     return false;
376   }
377   else{
378     *size = retval.encoded;
379   }
380   
381   return true;
382 }
383
384
385
386 // Used when generating an indication header 
387 bool e2sm_indication::set_header_fields(E2N_E2SM_gNB_X2_indicationHeader_t *header,  e2sm_header_helper &helper){
388
389   if (header == 0){
390     error_string = "Invalid reference for E2SM Indication Header set fields";
391     return false;
392   }
393   
394   
395   header->interfaceDirection = helper.interface_direction;
396   header->interface_ID.present = E2N_Interface_ID_PR_global_gNB_ID;
397   header->interface_ID.choice.global_gNB_ID = &gNodeB_ID;
398
399
400   // to do : need to put correct code here for upding plmn id and gNodeB
401   // for now just place holders :
402   memcpy(gNodeB_ID.pLMN_Identity.buf, helper.plmn_id.c_str(), 3);
403   gNodeB_ID.pLMN_Identity.size = 3;
404   
405   memcpy(gNodeB_ID.gNB_ID.choice.gNB_ID.buf, helper.egNB_id.c_str(), 3);
406   gNodeB_ID.gNB_ID.choice.gNB_ID.size = 3;
407   
408   // we only do global gNodeB id for now, not eNodeB
409   gNodeB_ID.gNB_ID.present = E2N_GNB_ID_PR_gNB_ID;
410
411   return true;
412   
413 };
414
415
416 // used when decoding an indication header
417 bool e2sm_indication::get_header_fields(E2N_E2SM_gNB_X2_indicationHeader_t *header,  e2sm_header_helper &helper){
418
419   if (header == 0){
420     error_string = "Invalid reference for E2SM Indication header get fields";
421     return false;
422   }
423   
424   helper.interface_direction = header->interfaceDirection;
425   helper.plmn_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->pLMN_Identity.buf, header->interface_ID.choice.global_gNB_ID->pLMN_Identity.size);
426   helper.egNB_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.buf, header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.size);
427   
428   // to do : add code to decipher plmn and global gnodeb from ints (since that is likely the convention for packing)
429
430   return true;
431 }
432
433
434
435 // Used when generating an indication message 
436 bool   e2sm_indication::set_message_fields(E2N_E2SM_gNB_X2_indicationMessage_t *interface_message,  e2sm_message_helper &helper){
437
438   if(interface_message == 0){
439     error_string = "Invalid reference for E2SM Indication Message set fields";
440     return false;
441   }
442
443   // interface-message is an octet string. just point it to the buffer
444   interface_message->interfaceMessage.buf = &(helper.x2ap_pdu[0]);
445   interface_message->interfaceMessage.size = helper.x2ap_pdu_size;
446
447   return true;
448   
449 };
450
451 // used when decoding an indication message
452 bool e2sm_indication::get_message_fields( E2N_E2SM_gNB_X2_indicationMessage_t *interface_message, e2sm_message_helper &helper){
453
454   
455   if(interface_message == 0){
456     error_string = "Invalid reference for E2SM Indication Message get fields";
457     return false;
458   }
459
460   // interface message is an octet string
461   helper.x2ap_pdu = interface_message->interfaceMessage.buf;;
462   helper.x2ap_pdu_size = interface_message->interfaceMessage.size;
463
464   return true;
465   
466 }
467   
468
469    
470 // initialize
471 e2sm_control::e2sm_control(void) {
472   
473   memset(&gNodeB_ID, 0, sizeof(E2N_GlobalGNB_ID_t));
474     
475   // allocate space for gNodeB id  (used for encoding)
476   gNodeB_ID.gNB_ID.choice.gNB_ID.buf = (uint8_t *)calloc(4, sizeof(uint8_t));
477   assert(gNodeB_ID.gNB_ID.choice.gNB_ID.buf != 0);
478     
479   // allocate space for plmn identity  (used for encoding)
480   gNodeB_ID.pLMN_Identity.buf = (uint8_t *) calloc(4, sizeof(uint8_t));
481   assert(gNodeB_ID.pLMN_Identity.buf != 0);
482
483   header = 0;
484   header = (E2N_E2SM_gNB_X2_controlHeader_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_controlHeader_t));
485   assert(header != 0);
486
487   message = 0;
488   message = (E2N_E2SM_gNB_X2_controlMessage_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_controlMessage_t));
489   assert(message != 0);
490 }
491   
492 e2sm_control::~e2sm_control(void){
493   mdclog_write(MDCLOG_DEBUG, "Freeing E2SM Control  object memory");
494
495   free(gNodeB_ID.gNB_ID.choice.gNB_ID.buf);
496   free(gNodeB_ID.pLMN_Identity.buf);
497   header->interface_ID.choice.global_gNB_ID = 0;
498   ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_controlHeader, header);
499
500   message->interfaceMessage.buf = 0;
501   ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_controlMessage, message);
502
503   mdclog_write(MDCLOG_DEBUG, "Freed E2SM Control  object memory");
504     
505 }
506   
507   
508
509 bool e2sm_control::encode_control_header(unsigned char *buf, size_t *size, e2sm_header_helper &helper){
510     
511   bool res;
512   res = set_header_fields(header, helper);
513   if (!res){
514     return false;
515   }
516
517   int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_controlHeader, header, errbuf, &errbuf_len);
518   if(ret_constr){
519     error_string.assign(&errbuf[0], errbuf_len);
520     error_string = "E2SM Control Header Constraint failed : " + error_string;
521
522     return false;
523   }
524
525   asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_controlHeader, header, buf, *size);
526
527   if(retval.encoded == -1){
528     error_string.assign(strerror(errno));
529     error_string = "Error encoding E2SM Control Header. Reason = " + error_string;
530     return false;
531   }
532   else if (retval.encoded > *size){
533     std::stringstream ss;
534     ss  <<"Error encoding E2N_E2SM Control Header . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
535     error_string = ss.str();
536     return false;
537   }
538   else{
539     *size = retval.encoded;
540   }
541     
542   return true;
543 }
544
545
546 bool e2sm_control::encode_control_message(unsigned char *buf, size_t *size, e2sm_message_helper &helper){
547
548   set_message_fields(message, helper); 
549
550   int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_controlMessage, message, errbuf, &errbuf_len);
551   if(ret_constr){
552     error_string.assign(&errbuf[0], errbuf_len);
553     error_string = "E2SM Control Message Constraint failed : " + error_string;
554     return false;
555   }
556
557   asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_controlMessage, message, buf, *size);
558   if(retval.encoded == -1){
559     error_string.assign(strerror(errno));
560     error_string = "Error encoding E2SM Control Message. Reason = " + error_string;
561     return false;
562   }
563   else if (retval.encoded > *size){
564     std::stringstream ss;
565     ss  <<"Error encoding E2SM Control Message . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
566     error_string = ss.str();
567     
568     return false;
569   }
570   else{
571     *size = retval.encoded;
572   }
573   
574   return true;
575 }
576
577
578
579 // Used when generating an indication header 
580 bool e2sm_control::set_header_fields(E2N_E2SM_gNB_X2_controlHeader_t *header,  e2sm_header_helper &helper){
581
582   if (header == 0){
583     error_string = "Invalid reference for E2SM Control Header set fields";
584     return false;
585   }
586   
587   
588   header->interfaceDirection = helper.interface_direction;
589   header->interface_ID.present = E2N_Interface_ID_PR_global_gNB_ID;
590   header->interface_ID.choice.global_gNB_ID = &gNodeB_ID;
591
592
593   // to do : need to put correct code here for upding plmn id and gNodeB
594   // for now just place holders :
595   memcpy(gNodeB_ID.pLMN_Identity.buf, helper.plmn_id.c_str(), 3);
596   gNodeB_ID.pLMN_Identity.size = 3;
597   
598   memcpy(gNodeB_ID.gNB_ID.choice.gNB_ID.buf, helper.egNB_id.c_str(), 3);
599   gNodeB_ID.gNB_ID.choice.gNB_ID.size = 3;
600   
601   // we only do global gNodeB id for now, not eNodeB
602   gNodeB_ID.gNB_ID.present = E2N_GNB_ID_PR_gNB_ID;
603
604   return true;
605   
606 };
607
608
609 // used when decoding an indication header
610 bool e2sm_control::get_header_fields(E2N_E2SM_gNB_X2_controlHeader_t *header,  e2sm_header_helper &helper){
611
612   if (header == 0){
613     error_string = "Invalid reference for E2SM Control header get fields";
614     return false;
615   }
616   
617   helper.interface_direction = header->interfaceDirection;
618   helper.plmn_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->pLMN_Identity.buf, header->interface_ID.choice.global_gNB_ID->pLMN_Identity.size);
619   helper.egNB_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.buf, header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.size);
620   
621   // to do : add code to decipher plmn and global gnodeb from ints (since that is likely the convention for packing)
622
623   return true;
624 }
625
626
627
628 // Used when generating an indication message 
629 bool   e2sm_control::set_message_fields(E2N_E2SM_gNB_X2_controlMessage_t *interface_message,  e2sm_message_helper &helper){
630
631   if(interface_message == 0){
632     error_string = "Invalid reference for E2SM Control Message set fields";
633     return false;
634   }
635
636   // interface-message is an octet string. just point it to the buffer
637   interface_message->interfaceMessage.buf = &(helper.x2ap_pdu[0]);
638   interface_message->interfaceMessage.size = helper.x2ap_pdu_size;
639
640   return true;
641   
642 };
643
644 // used when decoding an indication message
645 bool e2sm_control::get_message_fields( E2N_E2SM_gNB_X2_controlMessage_t *interface_message, e2sm_message_helper &helper){
646
647   
648   if(interface_message == 0){
649     error_string = "Invalid reference for E2SM Control Message get fields";
650     return false;
651   }
652
653   // interface message is an octet string
654   helper.x2ap_pdu = interface_message->interfaceMessage.buf;;
655   helper.x2ap_pdu_size = interface_message->interfaceMessage.size;
656
657   return true;
658   
659 }
660