gtp_itf.cpp 48.9 KB
Newer Older
Laurent Thomas's avatar
Laurent Thomas committed
1 2 3 4 5 6
#include <map>
using namespace std;

#ifdef __cplusplus
extern "C" {
#endif
Laurent Thomas's avatar
Laurent Thomas committed
7 8 9 10 11 12 13 14 15 16 17 18
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netdb.h>

#include <openair2/COMMON/platform_types.h>
#include <openair3/UTILS/conversions.h>
#include "common/utils/LOG/log.h"
#include <common/utils/ocp_itti/intertask_interface.h>
#include <openair2/COMMON/gtpv1_u_messages_types.h>
#include <openair3/ocp-gtpu/gtp_itf.h>
Laurent Thomas's avatar
Laurent Thomas committed
19
#include <openair2/LAYER2/PDCP_v10.1.0/pdcp.h>
20
#include <openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h>
21
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
22
#include "sim.h"
Laurent Thomas's avatar
Laurent Thomas committed
23 24 25 26 27 28 29 30 31 32 33 34

#pragma pack(1)

typedef struct Gtpv1uMsgHeader {
  uint8_t PN:1;
  uint8_t S:1;
  uint8_t E:1;
  uint8_t spare:1;
  uint8_t PT:1;
  uint8_t version:3;
  uint8_t msgType;
  uint16_t msgLength;
Laurent Thomas's avatar
Laurent Thomas committed
35
  teid_t teid;
Laurent Thomas's avatar
Laurent Thomas committed
36 37
} __attribute__((packed)) Gtpv1uMsgHeaderT;

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
//TS 38.425, Figure 5.5.2.2-1
typedef struct DlDataDeliveryStatus_flags {
  uint8_t LPR:1;                    //Lost packet report
  uint8_t FFI:1;                    //Final Frame Ind
  uint8_t deliveredPdcpSn:1;        //Highest Delivered NR PDCP SN Ind
  uint8_t transmittedPdcpSn:1;      //Highest Transmitted NR PDCP SN Ind
  uint8_t pduType:4;                //PDU type
  uint8_t CR:1;                     //Cause Report
  uint8_t deliveredReTxPdcpSn:1;    //Delivered retransmitted NR PDCP SN Ind
  uint8_t reTxPdcpSn:1;             //Retransmitted NR PDCP SN Ind
  uint8_t DRI:1;                    //Data Rate Indication
  uint8_t deliveredPdcpSnRange:1;   //Delivered NR PDCP SN Range Ind
  uint8_t spare:3;
  uint32_t drbBufferSize;            //Desired buffer size for the data radio bearer
} __attribute__((packed)) DlDataDeliveryStatus_flagsT;

54 55 56 57 58 59 60
typedef struct Gtpv1uMsgHeaderOptFields {
  uint8_t seqNum1Oct;
  uint8_t seqNum2Oct;
  uint8_t NPDUNum;
  uint8_t NextExtHeaderType;    
} __attribute__((packed)) Gtpv1uMsgHeaderOptFieldsT;

61 62 63 64
#define DL_PDU_SESSION_INFORMATION 0
#define UL_PDU_SESSION_INFORMATION 1

  typedef struct PDUSessionContainer {
65 66 67
  uint8_t spare:4;
  uint8_t PDU_type:4;
  uint8_t QFI:6;
68 69
  uint8_t Reflective_QoS_activation:1;
  uint8_t Paging_Policy_Indicator:1;
70 71 72 73 74
} __attribute__((packed)) PDUSessionContainerT;

typedef struct Gtpv1uExtHeader {
  uint8_t ExtHeaderLen;
  PDUSessionContainerT pdusession_cntr;
75
  uint8_t NextExtHeaderType;
76 77
}__attribute__((packed)) Gtpv1uExtHeaderT;

Laurent Thomas's avatar
Laurent Thomas committed
78 79
#pragma pack()

80 81
// TS 29.281, fig 5.2.1-3
#define PDU_SESSION_CONTAINER       (0x85)
82 83
#define NR_RAN_CONTAINER            (0x84)

84 85 86 87
// TS 29.281, 5.2.1
#define EXT_HDR_LNTH_OCTET_UNITS    (4)
#define NO_MORE_EXT_HDRS            (0)

Laurent Thomas's avatar
Laurent Thomas committed
88 89
// TS 29.060, table 7.1 defines the possible message types
// here are all the possible messages (3GPP R16)
Laurent Thomas's avatar
Laurent Thomas committed
90 91 92 93 94 95 96 97
#define GTP_ECHO_REQ                                         (1)
#define GTP_ECHO_RSP                                         (2)
#define GTP_ERROR_INDICATION                                 (26)
#define GTP_SUPPORTED_EXTENSION_HEADER_INDICATION            (31)
#define GTP_END_MARKER                                       (254)
#define GTP_GPDU                                             (255)


Laurent THOMAS's avatar
Laurent THOMAS committed
98
typedef struct gtpv1u_bearer_s {
Laurent Thomas's avatar
Laurent Thomas committed
99 100 101 102 103 104 105 106
  /* TEID used in dl and ul */
  teid_t          teid_incoming;                ///< eNB TEID
  teid_t          teid_outgoing;                ///< Remote TEID
  in_addr_t       outgoing_ip_addr;
  struct in6_addr outgoing_ip6_addr;
  tcp_udp_port_t  outgoing_port;
  uint16_t        seqNum;
  uint8_t         npduNum;
107
  int outgoing_qfi;
Laurent THOMAS's avatar
Laurent THOMAS committed
108
} gtpv1u_bearer_t;
Laurent Thomas's avatar
Laurent Thomas committed
109 110

typedef struct {
111
  map<ue_id_t, gtpv1u_bearer_t> bearers;
112
  teid_t outgoing_teid;
Laurent Thomas's avatar
Laurent Thomas committed
113 114 115
} teidData_t;

typedef struct {
116
  ue_id_t ue_id;
Laurent THOMAS's avatar
Laurent THOMAS committed
117
  ebi_t incoming_rb_id;
Laurent Thomas's avatar
Laurent Thomas committed
118
  gtpCallback callBack;
119
  teid_t outgoing_teid;
athanassopoulos's avatar
athanassopoulos committed
120
  gtpCallbackSDAP callBackSDAP;
121
  int pdusession_id;
122
} ueidData_t;
Laurent Thomas's avatar
Laurent Thomas committed
123 124 125 126

class gtpEndPoint {
 public:
  openAddr_t addr;
Laurent Thomas's avatar
Laurent Thomas committed
127 128
  uint8_t foundAddr[20];
  int foundAddrLen;
129
  int ipVersion;
130 131
  map<uint64_t,teidData_t> ue2te_mapping;
  map<uint64_t,ueidData_t> te2ue_mapping;
132 133 134 135
  // we use the same port number for source and destination address
  // this allow using non standard gtp port number (different from 2152)
  // and so, for example tu run 4G and 5G cores on one system
  tcp_udp_port_t get_dstport() {
Laurent THOMAS's avatar
Laurent THOMAS committed
136
    return (tcp_udp_port_t)atol(addr.destinationService);
137
  }
Laurent Thomas's avatar
Laurent Thomas committed
138 139 140 141 142 143
};

class gtpEndPoints {
 public:
  pthread_mutex_t gtp_lock=PTHREAD_MUTEX_INITIALIZER;
  // the instance id will be the Linux socket handler, as this is uniq
144
  map<uint64_t, gtpEndPoint> instances;
145

146
  gtpEndPoints() {
Robert Schmidt's avatar
Robert Schmidt committed
147 148 149
    unsigned int seed;
    fill_random(&seed, sizeof(seed));
    srandom(seed);
150 151
  }

152 153
  ~gtpEndPoints() {
    // automatically close all sockets on quit
154
    for (const auto &p : instances)
155 156
      close(p.first);
  }
Laurent Thomas's avatar
Laurent Thomas committed
157 158 159 160
};

gtpEndPoints globGtp;

161
// note TEid 0 is reserved for specific usage: echo req/resp, error and supported extensions
162
static  teid_t gtpv1uNewTeid(void) {
Laurent Thomas's avatar
Laurent Thomas committed
163 164 165 166 167 168 169 170
#ifdef GTPV1U_LINEAR_TEID_ALLOCATION
  g_gtpv1u_teid = g_gtpv1u_teid + 1;
  return g_gtpv1u_teid;
#else
  return random() + random() % (RAND_MAX - 1) + 1;
#endif
}

171
instance_t legacyInstanceMapping=0;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
#define compatInst(a) ((a)==0 || (a)==INSTANCE_DEFAULT ? legacyInstanceMapping:a)

#define getInstRetVoid(insT)                                    \
  auto instChk=globGtp.instances.find(compatInst(insT));    \
  if (instChk == globGtp.instances.end()) {                        \
    LOG_E(GTPU,"try to get a gtp-u not existing output\n");     \
    pthread_mutex_unlock(&globGtp.gtp_lock);                    \
    return;                                                     \
  }                                                             \
  gtpEndPoint * inst=&instChk->second;
  
#define getInstRetInt(insT)                                    \
  auto instChk=globGtp.instances.find(compatInst(insT));    \
  if (instChk == globGtp.instances.end()) {                        \
    LOG_E(GTPU,"try to get a gtp-u not existing output\n");     \
    pthread_mutex_unlock(&globGtp.gtp_lock);                    \
    return GTPNOK;                                                     \
  }                                                             \
  gtpEndPoint * inst=&instChk->second;


193 194
#define getUeRetVoid(insT, Ue)                                            \
    auto ptrUe=insT->ue2te_mapping.find(Ue);                        \
195
                                                                        \
196 197
  if (  ptrUe==insT->ue2te_mapping.end() ) {                          \
    LOG_E(GTPU, "[%ld] gtpv1uSend failed: while getting ue id %ld in hashtable ue_mapping\n", instance, ue_id); \
198 199 200
    pthread_mutex_unlock(&globGtp.gtp_lock);                            \
    return;                                                             \
  }
201
  
202 203
#define getUeRetInt(insT, Ue)                                            \
    auto ptrUe=insT->ue2te_mapping.find(Ue);                        \
204
                                                                        \
205 206
  if (  ptrUe==insT->ue2te_mapping.end() ) {                          \
    LOG_E(GTPU, "[%ld] gtpv1uSend failed: while getting ue id %ld in hashtable ue_mapping\n", instance, ue_id); \
207 208 209 210 211
    pthread_mutex_unlock(&globGtp.gtp_lock);                            \
    return GTPNOK;                                                             \
  }
  
#define HDR_MAX 256 // 256 is supposed to be larger than any gtp header
212 213 214 215 216 217 218 219 220 221 222 223 224 225
static int gtpv1uCreateAndSendMsg(int h,
                                  uint32_t peerIp,
                                  uint16_t peerPort,
                                  int msgType,
                                  teid_t teid,
                                  uint8_t *Msg,
                                  int msgLen,
                                  bool seqNumFlag,
                                  bool npduNumFlag,
                                  int seqNum,
                                  int npduNum,
                                  int extHdrType,
                                  uint8_t *extensionHeader_buffer,
                                  uint8_t extensionHeader_length) {
226
  LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid);
Laurent Thomas's avatar
Laurent Thomas committed
227

228 229
  uint8_t buffer[msgLen+HDR_MAX]; 
  uint8_t *curPtr=buffer;
Laurent Thomas's avatar
Laurent Thomas committed
230
  Gtpv1uMsgHeaderT      *msgHdr = (Gtpv1uMsgHeaderT *)buffer ;
231
  // N should be 0 for us (it was used only in 2G and 3G)
Laurent Thomas's avatar
Laurent Thomas committed
232 233
  msgHdr->PN=npduNumFlag;
  msgHdr->S=seqNumFlag;
234
  msgHdr->E = extHdrType != NO_MORE_EXT_HDRS;
Laurent Thomas's avatar
Laurent Thomas committed
235
  msgHdr->spare=0;
236
  //PT=0 is for GTP' TS 32.295 (charging)
Laurent Thomas's avatar
Laurent Thomas committed
237 238
  msgHdr->PT=1;
  msgHdr->version=1;
239
  msgHdr->msgType=msgType;
Laurent Thomas's avatar
Laurent Thomas committed
240 241
  msgHdr->teid=htonl(teid);

242
  curPtr+=sizeof(Gtpv1uMsgHeaderT);
243

244 245 246 247 248 249 250
  if (seqNumFlag || (extHdrType != NO_MORE_EXT_HDRS) || npduNumFlag) {
    *(uint16_t *)curPtr = seqNumFlag ? seqNum : 0x0000;
    curPtr+=sizeof(uint16_t);
    *(uint8_t *)curPtr = npduNumFlag ? npduNum : 0x00;
    curPtr++;
    *(uint8_t *)curPtr = extHdrType;
    curPtr++;
251 252
  }

253 254 255 256 257 258 259 260 261 262
  // Bug: if there is more than one extension, infinite loop on extensionHeader_buffer
  while (extHdrType != NO_MORE_EXT_HDRS) {
    if (extensionHeader_length > 0) {
      memcpy(curPtr, extensionHeader_buffer, extensionHeader_length);
      curPtr += extensionHeader_length;
      LOG_D(GTPU, "Extension Header for DDD added. The length is: %d, extension header type is: %x \n", extensionHeader_length, *((uint8_t *)(buffer + 11)));
      extHdrType = extensionHeader_buffer[extensionHeader_length - 1];
      LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *)(buffer + 11)));
    } else {
      LOG_W(GTPU, "Extension header type not supported, returning... \n");
263 264
    }
  }
265

266
  if (Msg!= NULL){
267 268
    memcpy(curPtr, Msg, msgLen);
    curPtr+=msgLen;
Laurent Thomas's avatar
Laurent Thomas committed
269 270
  }

271 272
  msgHdr->msgLength = htons(curPtr-(buffer+sizeof(Gtpv1uMsgHeaderT)));
  AssertFatal(curPtr-(buffer+msgLen) < HDR_MAX, "fixed max size of all headers too short");
273
  // Fix me: add IPv6 support, using flag ipVersion
274
  struct sockaddr_in to= {0};
Laurent Thomas's avatar
Laurent Thomas committed
275 276 277
  to.sin_family      = AF_INET;
  to.sin_port        = htons(peerPort);
  to.sin_addr.s_addr = peerIp ;
278
  LOG_D(GTPU,"sending packet size: %ld to %s\n",curPtr-buffer, inet_ntoa(to.sin_addr) );
279
  int ret;
Laurent THOMAS's avatar
Laurent THOMAS committed
280

281 282 283
  if ((ret=sendto(h, (void *)buffer, curPtr-buffer, 0,(struct sockaddr *)&to, sizeof(to) )) != curPtr-buffer ) {
    LOG_E(GTPU, "[SD %d] Failed to send data to " IPV4_ADDR " on port %d, buffer size %lu, ret: %d, errno: %d\n",
          h, IPV4_ADDR_FORMAT(peerIp), peerPort, curPtr-buffer, ret, errno);
Laurent Thomas's avatar
Laurent Thomas committed
284 285 286 287 288 289
    return GTPNOK;
  }

  return  !GTPNOK;
}

290
static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) {
Laurent Thomas's avatar
Laurent Thomas committed
291 292
  uint8_t *buffer=req->buffer+req->offset;
  size_t length=req->length;
293 294
  ue_id_t ue_id=req->ue_id;
  int  bearer_id=req->bearer_id;
Laurent Thomas's avatar
Laurent Thomas committed
295
  pthread_mutex_lock(&globGtp.gtp_lock);
296
  getInstRetVoid(compatInst(instance));
297
  getUeRetVoid(inst, ue_id);
Laurent Thomas's avatar
Laurent Thomas committed
298

299
  auto ptr2=ptrUe->second.bearers.find(bearer_id);
Laurent Thomas's avatar
Laurent Thomas committed
300

301 302
  if ( ptr2 == ptrUe->second.bearers.end() ) {
    LOG_E(GTPU,"[%ld] GTP-U instance: sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id);
Laurent Thomas's avatar
Laurent Thomas committed
303 304
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
305 306
  }

307 308
  LOG_D(GTPU,"[%ld] sending a packet to UE:RAB:teid %lx/%x/%x, len %lu, oldseq %d, oldnum %d\n",
        instance, ue_id, bearer_id,ptr2->second.teid_outgoing,length, ptr2->second.seqNum,ptr2->second.npduNum );
309 310

  if(seqNumFlag)
311
    ptr2->second.seqNum++;
312 313

  if(npduNumFlag)
314
    ptr2->second.npduNum++;
315

316
  // copy to release the mutex
Laurent THOMAS's avatar
Laurent THOMAS committed
317
  gtpv1u_bearer_t tmp=ptr2->second;
318
  pthread_mutex_unlock(&globGtp.gtp_lock);
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347

  if (tmp.outgoing_qfi != -1) {
    Gtpv1uExtHeaderT ext = { 0 };
    ext.ExtHeaderLen = 1; // in quad bytes  EXT_HDR_LNTH_OCTET_UNITS
    ext.pdusession_cntr.spare = 0;
    ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION;
    ext.pdusession_cntr.QFI = tmp.outgoing_qfi;
    ext.pdusession_cntr.Reflective_QoS_activation = false;
    ext.pdusession_cntr.Paging_Policy_Indicator = false;
    ext.NextExtHeaderType = NO_MORE_EXT_HDRS;

    gtpv1uCreateAndSendMsg(compatInst(instance),
                           tmp.outgoing_ip_addr,
                           tmp.outgoing_port,
                           GTP_GPDU,
                           tmp.teid_outgoing,
                           buffer,
                           length,
                           seqNumFlag,
                           npduNumFlag,
                           tmp.seqNum,
                           tmp.npduNum,
                           PDU_SESSION_CONTAINER,
                           (uint8_t *)&ext,
                           sizeof(ext));
  } else {
    gtpv1uCreateAndSendMsg(
        compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, buffer, length, seqNumFlag, npduNumFlag, tmp.seqNum, tmp.npduNum, NO_MORE_EXT_HDRS, NULL, 0);
  }
348 349
}

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
static void fillDlDeliveryStatusReport(extensionHeader_t *extensionHeader, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN){

  extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+(NR_PDCP_PDU_SN>0?3:0)+(NR_PDCP_PDU_SN>0?1:0)+1)/4;
  DlDataDeliveryStatus_flagsT DlDataDeliveryStatus;
  DlDataDeliveryStatus.deliveredPdcpSn = 0;
  DlDataDeliveryStatus.transmittedPdcpSn= NR_PDCP_PDU_SN>0?1:0;
  DlDataDeliveryStatus.pduType = 1;
  DlDataDeliveryStatus.drbBufferSize = htonl(RLC_buffer_availability);
  memcpy(extensionHeader->buffer+1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT));
  uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT)+1;

  if(NR_PDCP_PDU_SN>0){
    extensionHeader->buffer[offset] =   (NR_PDCP_PDU_SN >> 16) & 0xff;
    extensionHeader->buffer[offset+1] = (NR_PDCP_PDU_SN >> 8) & 0xff;
    extensionHeader->buffer[offset+2] = NR_PDCP_PDU_SN & 0xff;
    LOG_D(GTPU, "Octets reporting NR_PDCP_PDU_SN, extensionHeader->buffer[offset]: %u, extensionHeader->buffer[offset+1]:%u, extensionHeader->buffer[offset+2]:%u \n", extensionHeader->buffer[offset], extensionHeader->buffer[offset+1],extensionHeader->buffer[offset+2]);
    extensionHeader->buffer[offset+3] = 0x00; //Padding octet
    offset = offset+3;
  }
  extensionHeader->buffer[offset] = 0x00; //No more extension headers
  /*Total size of DDD_status PDU = size of mandatory part +
   * 3 octets for highest transmitted/delivered PDCP SN +
   * 1 octet for padding + 1 octet for next extension header type,
   * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/
  extensionHeader->length  = 1+sizeof(DlDataDeliveryStatus_flagsT)+
                              (NR_PDCP_PDU_SN>0?3:0)+
                              (NR_PDCP_PDU_SN>0?1:0)+1;
}

static void gtpv1uSendDlDeliveryStatus(instance_t instance, gtpv1u_DU_buffer_report_req_t *req){
380 381
  ue_id_t ue_id=req->ue_id;
  int  bearer_id=req->pdusession_id;
382
  pthread_mutex_lock(&globGtp.gtp_lock);
383
  getInstRetVoid(compatInst(instance));
384
  getUeRetVoid(inst, ue_id);
385

386
  auto ptr2=ptrUe->second.bearers.find(bearer_id);
387

388 389
  if ( ptr2 == ptrUe->second.bearers.end() ) {
    LOG_D(GTPU,"GTP-U instance: %ld sending a packet to a non existant UE ID:RAB: %lu/%x\n", instance, ue_id, bearer_id);
390 391 392 393 394 395 396 397
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
  }

  extensionHeader_t *extensionHeader;
  extensionHeader = (extensionHeader_t *) calloc(1, sizeof(extensionHeader_t));
  fillDlDeliveryStatusReport(extensionHeader, req->buffer_availability,0);

398 399
  LOG_I(GTPU,"[%ld] GTP-U sending DL Data Delivery status to UE ID:RAB:teid %lu/%x/%x, oldseq %d, oldnum %d\n",
        instance, ue_id, bearer_id,ptr2->second.teid_outgoing, ptr2->second.seqNum,ptr2->second.npduNum );
400 401 402
  // copy to release the mutex
  gtpv1u_bearer_t tmp=ptr2->second;
  pthread_mutex_unlock(&globGtp.gtp_lock);
403 404
  gtpv1uCreateAndSendMsg(
      compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length);
405 406
}

407 408 409
static void gtpv1uEndTunnel(instance_t instance, gtpv1u_tunnel_data_req_t *req) {
  ue_id_t ue_id=req->ue_id;
  int  bearer_id=req->bearer_id;
410
  pthread_mutex_lock(&globGtp.gtp_lock);
411
  getInstRetVoid(compatInst(instance));
412
  getUeRetVoid(inst, ue_id);
413

414
  auto ptr2=ptrUe->second.bearers.find(bearer_id);
415

416 417
  if ( ptr2 == ptrUe->second.bearers.end() ) {
    LOG_E(GTPU,"[%ld] GTP-U sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id);
418 419
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
420
  }
421

422 423
  LOG_D(GTPU,"[%ld] sending a end packet packet to UE:RAB:teid %lx/%x/%x\n",
        instance, ue_id, bearer_id,ptr2->second.teid_outgoing);
Laurent THOMAS's avatar
Laurent THOMAS committed
424
  gtpv1u_bearer_t tmp=ptr2->second;
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
  pthread_mutex_unlock(&globGtp.gtp_lock);
  Gtpv1uMsgHeaderT  msgHdr;
  // N should be 0 for us (it was used only in 2G and 3G)
  msgHdr.PN=0;
  msgHdr.S=0;
  msgHdr.E=0;
  msgHdr.spare=0;
  //PT=0 is for GTP' TS 32.295 (charging)
  msgHdr.PT=1;
  msgHdr.version=1;
  msgHdr.msgType=GTP_END_MARKER;
  msgHdr.msgLength=htons(0);
  msgHdr.teid=htonl(tmp.teid_outgoing);
  // Fix me: add IPv6 support, using flag ipVersion
  static struct sockaddr_in to= {0};
  to.sin_family      = AF_INET;
  to.sin_port        = htons(tmp.outgoing_port);
  to.sin_addr.s_addr = tmp.outgoing_ip_addr;
Laurent THOMAS's avatar
Laurent THOMAS committed
443
  char ip4[INET_ADDRSTRLEN];
Laurent THOMAS's avatar
Laurent THOMAS committed
444
  //char ip6[INET6_ADDRSTRLEN];
445
  LOG_D(GTPU,"[%ld] sending end packet to %s\n", instance, inet_ntoa(to.sin_addr) );
Laurent Thomas's avatar
Laurent Thomas committed
446

447 448
  if (sendto(compatInst(instance), (void *)&msgHdr, sizeof(msgHdr), 0,(struct sockaddr *)&to, sizeof(to) ) !=  sizeof(msgHdr)) {
    LOG_E(GTPU,
449
          "[%ld] Failed to send data to %s on port %d, buffer size %lu\n",
Laurent THOMAS's avatar
Laurent THOMAS committed
450
          compatInst(instance), inet_ntop(AF_INET, &tmp.outgoing_ip_addr, ip4, INET_ADDRSTRLEN), tmp.outgoing_port, sizeof(msgHdr));
451 452
  }
}
453

Laurent Thomas's avatar
Laurent Thomas committed
454 455 456 457 458 459 460 461 462 463 464 465
static  int udpServerSocket(openAddr_s addr) {
  LOG_I(GTPU, "Initializing UDP for local address %s with port %s\n", addr.originHost, addr.originService);
  int status;
  struct addrinfo hints= {0}, *servinfo, *p;
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_flags = AI_PASSIVE;

  if ((status = getaddrinfo(addr.originHost, addr.originService, &hints, &servinfo)) != 0) {
    LOG_E(GTPU,"getaddrinfo error: %s\n", gai_strerror(status));
    return -1;
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
466

Laurent Thomas's avatar
Laurent Thomas committed
467 468 469 470 471 472 473 474 475 476 477 478 479 480
  int sockfd=-1;

  // loop through all the results and bind to the first we can
  for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
                         p->ai_protocol)) == -1) {
      LOG_W(GTPU,"socket: %s\n", strerror(errno));
      continue;
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
      close(sockfd);
      LOG_W(GTPU,"bind: %s\n", strerror(errno));
      continue;
Laurent Thomas's avatar
Laurent Thomas committed
481 482 483
    } else {
      // We create the gtp instance on the socket
      globGtp.instances[sockfd].addr=addr;
484 485 486 487 488 489

      if (p->ai_family == AF_INET) {
        struct sockaddr_in *ipv4=(struct sockaddr_in *)p->ai_addr;
        memcpy(globGtp.instances[sockfd].foundAddr,
               &ipv4->sin_addr.s_addr, sizeof(ipv4->sin_addr.s_addr));
        globGtp.instances[sockfd].foundAddrLen=sizeof(ipv4->sin_addr.s_addr);
490
        globGtp.instances[sockfd].ipVersion=4;
491 492 493 494 495 496 497
        break;
      } else if (p->ai_family == AF_INET6) {
        LOG_W(GTPU,"Local address is IP v6\n");
        struct sockaddr_in6 *ipv6=(struct sockaddr_in6 *)p->ai_addr;
        memcpy(globGtp.instances[sockfd].foundAddr,
               &ipv6->sin6_addr.s6_addr, sizeof(ipv6->sin6_addr.s6_addr));
        globGtp.instances[sockfd].foundAddrLen=sizeof(ipv6->sin6_addr.s6_addr);
498
        globGtp.instances[sockfd].ipVersion=6;
499 500
      } else
        AssertFatal(false,"Local address is not IPv4 or IPv6");
Laurent Thomas's avatar
Laurent Thomas committed
501 502 503 504 505 506 507 508 509 510 511 512
    }

    break; // if we get here, we must have connected successfully
  }

  if (p == NULL) {
    // looped off the end of the list with no successful bind
    LOG_E(GTPU,"failed to bind socket: %s %s \n", addr.originHost, addr.originService);
    return -1;
  }

  freeaddrinfo(servinfo); // all done with this structure
Laurent Thomas's avatar
Laurent Thomas committed
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

  if (strlen(addr.destinationHost)>1) {
    struct addrinfo hints;
    memset(&hints,0,sizeof(hints));
    hints.ai_family=AF_UNSPEC;
    hints.ai_socktype=SOCK_DGRAM;
    hints.ai_protocol=0;
    hints.ai_flags=AI_PASSIVE|AI_ADDRCONFIG;
    struct addrinfo *res=0;
    int err=getaddrinfo(addr.destinationHost,addr.destinationService,&hints,&res);

    if (err==0) {
      for(p = res; p != NULL; p = p->ai_next) {
        if ((err=connect(sockfd,  p->ai_addr, p->ai_addrlen))==0)
          break;
      }
    }

    if (err)
      LOG_E(GTPU,"Can't filter remote host: %s, %s\n", addr.destinationHost,addr.destinationService);
  }

Laurent Thomas's avatar
Laurent Thomas committed
535 536
  int sendbuff = 1000*1000*10;
  AssertFatal(0==setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)),"");
537
  LOG_D(GTPU,"[%d] Created listener for paquets to: %s:%s, send buffer size: %d\n", sockfd, addr.originHost, addr.originService,sendbuff);
Laurent Thomas's avatar
Laurent Thomas committed
538 539 540
  return sockfd;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
541
instance_t gtpv1Init(openAddr_t context) {
Laurent Thomas's avatar
Laurent Thomas committed
542 543 544 545
  pthread_mutex_lock(&globGtp.gtp_lock);
  int id=udpServerSocket(context);

  if (id>=0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
546
    itti_subscribe_event_fd(TASK_GTPV1_U, id);
Laurent Thomas's avatar
Laurent Thomas committed
547 548 549 550
  } else
    LOG_E(GTPU,"can't create GTP-U instance\n");

  pthread_mutex_unlock(&globGtp.gtp_lock);
551
  LOG_I(GTPU, "Created gtpu instance id: %d\n", id);
Laurent Thomas's avatar
Laurent Thomas committed
552 553 554
  return id;
}

555
void GtpuUpdateTunnelOutgoingTeid(instance_t instance, ue_id_t ue_id, ebi_t bearer_id, teid_t newOutgoingTeid) {
556
  pthread_mutex_lock(&globGtp.gtp_lock);
557
  getInstRetVoid(compatInst(instance));
558
  getUeRetVoid(inst, ue_id);
559

560
  auto ptr2=ptrUe->second.bearers.find(bearer_id);
561

562 563
  if ( ptr2 == ptrUe->second.bearers.end() ) {
    LOG_E(GTPU,"[%ld] Update tunnel for a existing ue id %lu, but wrong bearer_id %u\n", instance, ue_id, bearer_id);
564 565
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
566 567 568
  }

  ptr2->second.teid_outgoing = newOutgoingTeid;
Laurent THOMAS's avatar
Laurent THOMAS committed
569
  LOG_I(GTPU, "[%ld] Tunnel Outgoing TEID updated to %x \n", instance, ptr2->second.teid_outgoing);
570 571
  pthread_mutex_unlock(&globGtp.gtp_lock);
  return;
572 573
}

574
teid_t newGtpuCreateTunnel(instance_t instance,
575
                           ue_id_t ue_id,
576 577 578 579 580 581 582 583
                           int incoming_bearer_id,
                           int outgoing_bearer_id,
                           teid_t outgoing_teid,
                           int outgoing_qfi,
                           transport_layer_addr_t remoteAddr,
                           int port,
                           gtpCallback callBack,
                           gtpCallbackSDAP callBackSDAP) {
Laurent Thomas's avatar
Laurent Thomas committed
584
  pthread_mutex_lock(&globGtp.gtp_lock);
585
  getInstRetInt(compatInst(instance));
586
  auto it=inst->ue2te_mapping.find(ue_id);
Laurent Thomas's avatar
Laurent Thomas committed
587

588
  if ( it != inst->ue2te_mapping.end() &&  it->second.bearers.find(outgoing_bearer_id) != it->second.bearers.end()) {
589
    LOG_W(GTPU,"[%ld] Create a config for a already existing GTP tunnel (ue id %lu)\n", instance, ue_id);
Laurent Thomas's avatar
Laurent Thomas committed
590 591 592
    inst->ue2te_mapping.erase(it);
  }

593
  teid_t incoming_teid=gtpv1uNewTeid();
Laurent Thomas's avatar
Laurent Thomas committed
594

Laurent THOMAS's avatar
Laurent THOMAS committed
595
  while ( inst->te2ue_mapping.find(incoming_teid) != inst->te2ue_mapping.end() ) {
596
    LOG_W(GTPU, "[%ld] generated a random Teid that exists, re-generating (%x)\n", instance, incoming_teid);
Laurent THOMAS's avatar
Laurent THOMAS committed
597
    incoming_teid=gtpv1uNewTeid();
Laurent Thomas's avatar
Laurent Thomas committed
598
  };
Laurent Thomas's avatar
Laurent Thomas committed
599

600
  inst->te2ue_mapping[incoming_teid].ue_id=ue_id;
Laurent Thomas's avatar
Laurent Thomas committed
601

602
  inst->te2ue_mapping[incoming_teid].incoming_rb_id= incoming_bearer_id;
603

604 605
  inst->te2ue_mapping[incoming_teid].outgoing_teid= outgoing_teid;

Laurent THOMAS's avatar
Laurent THOMAS committed
606
  inst->te2ue_mapping[incoming_teid].callBack=callBack;
607 608

  inst->te2ue_mapping[incoming_teid].callBackSDAP = callBackSDAP;
Laurent Thomas's avatar
Laurent Thomas committed
609

610
  inst->te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id;
Laurent Thomas's avatar
Laurent Thomas committed
611

612
  gtpv1u_bearer_t *tmp=&inst->ue2te_mapping[ue_id].bearers[outgoing_bearer_id];
Laurent Thomas's avatar
Laurent Thomas committed
613

Laurent Thomas's avatar
Laurent Thomas committed
614
  int addrs_length_in_bytes = remoteAddr.length / 8;
Laurent Thomas's avatar
Laurent Thomas committed
615

Laurent Thomas's avatar
Laurent Thomas committed
616 617 618 619
  switch (addrs_length_in_bytes) {
    case 4:
      memcpy(&tmp->outgoing_ip_addr,remoteAddr.buffer,4);
      break;
Laurent Thomas's avatar
Laurent Thomas committed
620

Laurent Thomas's avatar
Laurent Thomas committed
621 622 623 624
    case 16:
      memcpy(tmp->outgoing_ip6_addr.s6_addr,remoteAddr.buffer,
             16);
      break;
Laurent Thomas's avatar
Laurent Thomas committed
625

Laurent Thomas's avatar
Laurent Thomas committed
626 627
    case 20:
      memcpy(&tmp->outgoing_ip_addr,remoteAddr.buffer,4);
628
      memcpy(tmp->outgoing_ip6_addr.s6_addr,
Laurent Thomas's avatar
Laurent Thomas committed
629 630 631 632 633 634
             remoteAddr.buffer+4,
             16);

    default:
      AssertFatal(false, "SGW Address size impossible");
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
635

Laurent THOMAS's avatar
Laurent THOMAS committed
636
  tmp->teid_incoming = incoming_teid;
Laurent Thomas's avatar
Laurent Thomas committed
637
  tmp->outgoing_port=port;
Laurent THOMAS's avatar
Laurent THOMAS committed
638
  tmp->teid_outgoing= outgoing_teid;
639
  tmp->outgoing_qfi=outgoing_qfi;
Laurent Thomas's avatar
Laurent Thomas committed
640
  pthread_mutex_unlock(&globGtp.gtp_lock);
641 642
  char ip4[INET_ADDRSTRLEN];
  char ip6[INET6_ADDRSTRLEN];
643
  LOG_I(GTPU, "[%ld] Created tunnel for UE ID %lu, teid for DL: %x, teid for UL %x to remote IPv4: %s, IPv6 %s\n",
Laurent Thomas's avatar
Laurent Thomas committed
644
        instance,
645
        ue_id,
Laurent THOMAS's avatar
Laurent THOMAS committed
646
        tmp->teid_incoming,
647
        tmp->teid_outgoing,
648 649
        inet_ntop(AF_INET,(void *)&tmp->outgoing_ip_addr, ip4,INET_ADDRSTRLEN ),
        inet_ntop(AF_INET6,(void *)&tmp->outgoing_ip6_addr.s6_addr, ip6, INET6_ADDRSTRLEN));
Laurent THOMAS's avatar
Laurent THOMAS committed
650
  return incoming_teid;
Laurent Thomas's avatar
Laurent Thomas committed
651 652
}

Laurent THOMAS's avatar
Laurent THOMAS committed
653
int gtpv1u_create_s1u_tunnel(instance_t instance,
Laurent THOMAS's avatar
Laurent THOMAS committed
654 655
                             const gtpv1u_enb_create_tunnel_req_t  *create_tunnel_req,
                             gtpv1u_enb_create_tunnel_resp_t *create_tunnel_resp) {
656
  LOG_D(GTPU, "[%ld] Start create tunnels for UE ID %u, num_tunnels %d, sgw_S1u_teid %x\n",
Laurent Thomas's avatar
Laurent Thomas committed
657
        instance,
Laurent Thomas's avatar
Laurent Thomas committed
658 659 660
        create_tunnel_req->rnti,
        create_tunnel_req->num_tunnels,
        create_tunnel_req->sgw_S1u_teid[0]);
661 662 663 664 665 666 667 668
  pthread_mutex_lock(&globGtp.gtp_lock);
  getInstRetInt(compatInst(instance));
  
  tcp_udp_port_t dstport=inst->get_dstport();
  uint8_t addr[inst->foundAddrLen];
  memcpy(addr, inst->foundAddr, inst->foundAddrLen);
  pthread_mutex_unlock(&globGtp.gtp_lock);
  
Laurent Thomas's avatar
Laurent Thomas committed
669
  for (int i = 0; i < create_tunnel_req->num_tunnels; i++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
670 671 672 673
    AssertFatal(create_tunnel_req->eps_bearer_id[i] > 4,
                "From legacy code not clear, seems impossible (bearer=%d)\n",
                create_tunnel_req->eps_bearer_id[i]);
    int incoming_rb_id=create_tunnel_req->eps_bearer_id[i]-4;
674 675 676 677 678 679 680 681 682 683
    teid_t teid = newGtpuCreateTunnel(compatInst(instance),
                                      create_tunnel_req->rnti,
                                      incoming_rb_id,
                                      create_tunnel_req->eps_bearer_id[i],
                                      create_tunnel_req->sgw_S1u_teid[i],
                                      -1, // no pdu session in 4G
                                      create_tunnel_req->sgw_addr[i],
                                      dstport,
                                      pdcp_data_req,
                                      NULL);
Laurent Thomas's avatar
Laurent Thomas committed
684 685 686
    create_tunnel_resp->status=0;
    create_tunnel_resp->rnti=create_tunnel_req->rnti;
    create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels;
Laurent Thomas's avatar
Laurent Thomas committed
687
    create_tunnel_resp->enb_S1u_teid[i]=teid;
Laurent Thomas's avatar
Laurent Thomas committed
688
    create_tunnel_resp->eps_bearer_id[i] = create_tunnel_req->eps_bearer_id[i];
689 690
    memcpy(create_tunnel_resp->enb_addr.buffer,addr,sizeof(addr));
    create_tunnel_resp->enb_addr.length= sizeof(addr);
Laurent Thomas's avatar
Laurent Thomas committed
691 692 693 694 695
  }

  return !GTPNOK;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
696
int gtpv1u_update_s1u_tunnel(
Laurent Thomas's avatar
Laurent Thomas committed
697
  const instance_t                              instance,
698
  const gtpv1u_enb_create_tunnel_req_t *const   create_tunnel_req,
Laurent Thomas's avatar
Laurent Thomas committed
699 700
  const rnti_t                                  prior_rnti
) {
701
  LOG_D(GTPU, "[%ld] Start update tunnels for old RNTI %x, new RNTI %x, num_tunnels %d, sgw_S1u_teid %x, eps_bearer_id %x\n",
Laurent Thomas's avatar
Laurent Thomas committed
702
        instance,
Laurent Thomas's avatar
Laurent Thomas committed
703 704 705 706 707 708
        prior_rnti,
        create_tunnel_req->rnti,
        create_tunnel_req->num_tunnels,
        create_tunnel_req->sgw_S1u_teid[0],
        create_tunnel_req->eps_bearer_id[0]);
  pthread_mutex_lock(&globGtp.gtp_lock);
709
  getInstRetInt(compatInst(instance));
Laurent Thomas's avatar
Laurent Thomas committed
710

711
  if ( inst->ue2te_mapping.find(create_tunnel_req->rnti) == inst->ue2te_mapping.end() ) {
712 713
    LOG_E(GTPU,"[%ld] Update not already existing tunnel (new rnti %x, old rnti %x)\n", 
          instance, create_tunnel_req->rnti, prior_rnti);
Laurent Thomas's avatar
Laurent Thomas committed
714 715 716 717 718
  }

  auto it=inst->ue2te_mapping.find(prior_rnti);

  if ( it != inst->ue2te_mapping.end() ) {
719
    LOG_W(GTPU,"[%ld] Update a not existing tunnel, start create the new one (new ue id %u, old ue id %u)\n", instance, create_tunnel_req->rnti, prior_rnti);
Laurent Thomas's avatar
Laurent Thomas committed
720
    pthread_mutex_unlock(&globGtp.gtp_lock);
Laurent Thomas's avatar
Laurent Thomas committed
721
    gtpv1u_enb_create_tunnel_resp_t tmp;
Laurent THOMAS's avatar
Laurent THOMAS committed
722
    (void)gtpv1u_create_s1u_tunnel(instance, create_tunnel_req, &tmp);
Laurent Thomas's avatar
Laurent Thomas committed
723 724 725 726 727 728 729 730
    return 0;
  }

  inst->ue2te_mapping[create_tunnel_req->rnti]=it->second;
  inst->ue2te_mapping.erase(it);
  pthread_mutex_unlock(&globGtp.gtp_lock);
  return 0;
}
Laurent Thomas's avatar
Laurent Thomas committed
731

732 733 734
int gtpv1u_create_ngu_tunnel(  const instance_t instance,
                               const gtpv1u_gnb_create_tunnel_req_t   *const create_tunnel_req,
                               gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp) {
735
  LOG_D(GTPU, "[%ld] Start create tunnels for ue id %lu, num_tunnels %d, sgw_S1u_teid %x\n",
Laurent Thomas's avatar
Laurent Thomas committed
736
        instance,
737
        create_tunnel_req->ue_id,
738
        create_tunnel_req->num_tunnels,
739
        create_tunnel_req->outgoing_teid[0]);
740 741 742 743 744 745 746
  pthread_mutex_lock(&globGtp.gtp_lock);
  getInstRetInt(compatInst(instance));

  tcp_udp_port_t dstport = inst->get_dstport();
  uint8_t addr[inst->foundAddrLen];
  memcpy(addr, inst->foundAddr, inst->foundAddrLen);
  pthread_mutex_unlock(&globGtp.gtp_lock);
747
  for (int i = 0; i < create_tunnel_req->num_tunnels; i++) {
748
    teid_t teid = newGtpuCreateTunnel(instance,
749
                                      create_tunnel_req->ue_id,
750 751 752 753 754 755 756 757
                                      create_tunnel_req->incoming_rb_id[i],
                                      create_tunnel_req->pdusession_id[i],
                                      create_tunnel_req->outgoing_teid[i],
                                      create_tunnel_req->outgoing_qfi[i],
                                      create_tunnel_req->dst_addr[i],
                                      dstport,
                                      pdcp_data_req,
                                      sdap_data_req);
758
    create_tunnel_resp->status=0;
759
    create_tunnel_resp->ue_id=create_tunnel_req->ue_id;
760 761
    create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels;
    create_tunnel_resp->gnb_NGu_teid[i]=teid;
762 763
    memcpy(create_tunnel_resp->gnb_addr.buffer,addr,sizeof(addr));
    create_tunnel_resp->gnb_addr.length= sizeof(addr);
Laurent THOMAS's avatar
Laurent THOMAS committed
764 765
  }

766 767 768 769 770 771
  return !GTPNOK;
}

int gtpv1u_update_ngu_tunnel(
  const instance_t instanceP,
  const gtpv1u_gnb_create_tunnel_req_t *const  create_tunnel_req_pP,
772
  const ue_id_t prior_ueid
773
) {
Laurent THOMAS's avatar
Laurent THOMAS committed
774
  AssertFatal( false, "to be developped\n");
775 776 777
  return GTPNOK;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
778
int gtpv1u_create_x2u_tunnel(
Laurent Thomas's avatar
Laurent Thomas committed
779
  const instance_t instanceP,
Laurent Thomas's avatar
Laurent Thomas committed
780 781
  const gtpv1u_enb_create_x2u_tunnel_req_t   *const create_tunnel_req_pP,
  gtpv1u_enb_create_x2u_tunnel_resp_t *const create_tunnel_resp_pP) {
Laurent Thomas's avatar
Laurent Thomas committed
782 783
  AssertFatal( false, "to be developped\n");
}
Laurent Thomas's avatar
Laurent Thomas committed
784

785 786 787
int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id) {
  LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n",
        instance, ue_id);
Laurent Thomas's avatar
Laurent Thomas committed
788
  pthread_mutex_lock(&globGtp.gtp_lock);
789
  getInstRetInt(compatInst(instance));
790
  getUeRetInt(inst, ue_id);
Laurent Thomas's avatar
Laurent Thomas committed
791

Laurent THOMAS's avatar
Laurent THOMAS committed
792 793
  int nb=0;

794 795
  for (auto j=ptrUe->second.bearers.begin();
       j!=ptrUe->second.bearers.end();
Laurent THOMAS's avatar
Laurent THOMAS committed
796
       ++j) {
Laurent Thomas's avatar
Laurent Thomas committed
797
    inst->te2ue_mapping.erase(j->second.teid_incoming);
Laurent THOMAS's avatar
Laurent THOMAS committed
798 799
    nb++;
  }
Laurent Thomas's avatar
Laurent Thomas committed
800

801
  inst->ue2te_mapping.erase(ptrUe);
Laurent Thomas's avatar
Laurent Thomas committed
802
  pthread_mutex_unlock(&globGtp.gtp_lock);
803
  LOG_I(GTPU, "[%ld] Deleted all tunnels for ue id %ld (%d tunnels deleted)\n", instance, ue_id, nb);
Laurent Thomas's avatar
Laurent Thomas committed
804 805 806
  return !GTPNOK;
}

807
// Legacy delete tunnel finish by deleting all the ue id
808
// so the list of bearer provided is only a design bug
Laurent THOMAS's avatar
Laurent THOMAS committed
809 810
int gtpv1u_delete_s1u_tunnel( const instance_t instance,
                              const gtpv1u_enb_delete_tunnel_req_t *const req_pP) {
Laurent THOMAS's avatar
Laurent THOMAS committed
811
  return  newGtpuDeleteAllTunnels(instance, req_pP->rnti);
812
}
Laurent THOMAS's avatar
Laurent THOMAS committed
813

814 815 816
int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id) {
  LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n",
        instance, ue_id);
Laurent THOMAS's avatar
Laurent THOMAS committed
817
  pthread_mutex_lock(&globGtp.gtp_lock);
818
  getInstRetInt(compatInst(instance));
819
  getUeRetInt(inst, ue_id);
Laurent THOMAS's avatar
Laurent THOMAS committed
820
  int nb=0;
821

Laurent THOMAS's avatar
Laurent THOMAS committed
822
  for (int i=0; i<nbTunnels; i++) {
823
    auto ptr2=ptrUe->second.bearers.find(pdusession_id[i]);
Laurent THOMAS's avatar
Laurent THOMAS committed
824

825 826
    if ( ptr2 == ptrUe->second.bearers.end() ) {
      LOG_E(GTPU,"[%ld] GTP-U instance: delete of not existing tunnel UE ID:RAB: %ld/%x\n", instance, ue_id, pdusession_id[i]);
Laurent THOMAS's avatar
Laurent THOMAS committed
827 828 829 830 831
    } else {
      inst->te2ue_mapping.erase(ptr2->second.teid_incoming);
      nb++;
    }
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
832

833 834 835
  if (ptrUe->second.bearers.size() == 0 )
    // no tunnels on this ue id, erase the ue entry
    inst->ue2te_mapping.erase(ptrUe);
Laurent THOMAS's avatar
Laurent THOMAS committed
836

Laurent THOMAS's avatar
Laurent THOMAS committed
837
  pthread_mutex_unlock(&globGtp.gtp_lock);
838
  LOG_I(GTPU, "[%ld] Deleted all tunnels for ue id %lu (%d tunnels deleted)\n", instance, ue_id, nb);
Laurent THOMAS's avatar
Laurent THOMAS committed
839
  return !GTPNOK;
840 841
}

842
int gtpv1u_delete_x2u_tunnel( const instance_t instanceP,
Laurent THOMAS's avatar
Laurent THOMAS committed
843 844
                              const gtpv1u_enb_delete_tunnel_req_t *const req_pP) {
  LOG_E(GTPU,"x2 tunnel not implemented\n");
845
  return 0;
Laurent THOMAS's avatar
Laurent THOMAS committed
846 847
}

Laurent THOMAS's avatar
Laurent THOMAS committed
848
int gtpv1u_delete_ngu_tunnel( const instance_t instance,
Laurent THOMAS's avatar
Laurent THOMAS committed
849
                              gtpv1u_gnb_delete_tunnel_req_t *req) {
850
  return  newGtpuDeleteTunnels(instance, req->ue_id, req->num_pdusession, req->pdusession_id);
Laurent THOMAS's avatar
Laurent THOMAS committed
851
}
Laurent THOMAS's avatar
Laurent THOMAS committed
852

Laurent Thomas's avatar
Laurent Thomas committed
853 854 855 856 857
static int Gtpv1uHandleEchoReq(int h,
                               uint8_t *msgBuf,
                               uint32_t msgBufLen,
                               uint16_t peerPort,
                               uint32_t peerIp) {
858
  Gtpv1uMsgHeaderT      *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf;
Laurent THOMAS's avatar
Laurent THOMAS committed
859

860 861 862 863 864 865 866 867 868 869
  if ( msgHdr->version != 1 ||  msgHdr->PT != 1 ) {
    LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h);
    return GTPNOK;
  }

  if ( msgHdr->S != 1 ) {
    LOG_E(GTPU, "[%d] Received a echo request packet with no sequence number \n", h);
    return GTPNOK;
  }

Laurent THOMAS's avatar
Laurent THOMAS committed
870
  uint16_t seq=ntohs(*(uint16_t *)(msgHdr+1));
871
  LOG_D(GTPU, "[%d] Received a echo request, TEID: %d, seq: %hu\n", h, msgHdr->teid, seq);
Laurent THOMAS's avatar
Laurent THOMAS committed
872
  uint8_t recovery[2]= {14,0};
873
  return gtpv1uCreateAndSendMsg(h, peerIp, peerPort, GTP_ECHO_RSP, ntohl(msgHdr->teid), recovery, sizeof recovery, true, false, seq, 0, NO_MORE_EXT_HDRS, NULL, 0);
Laurent Thomas's avatar
Laurent Thomas committed
874 875 876 877 878 879 880
}

static int Gtpv1uHandleError(int h,
                             uint8_t *msgBuf,
                             uint32_t msgBufLen,
                             uint16_t peerPort,
                             uint32_t peerIp) {
881
  LOG_E(GTPU,"Hadle error to be dev\n");
Laurent Thomas's avatar
Laurent Thomas committed
882 883 884
  int rc = GTPNOK;
  return rc;
}
Laurent Thomas's avatar
Laurent Thomas committed
885

Laurent Thomas's avatar
Laurent Thomas committed
886
static int Gtpv1uHandleSupportedExt(int h,
Laurent Thomas's avatar
Laurent Thomas committed
887 888 889 890
                                    uint8_t *msgBuf,
                                    uint32_t msgBufLen,
                                    uint16_t peerPort,
                                    uint32_t peerIp) {
891
  LOG_E(GTPU,"Supported extensions to be dev\n");
Laurent Thomas's avatar
Laurent Thomas committed
892 893 894
  int rc = GTPNOK;
  return rc;
}
Laurent Thomas's avatar
Laurent Thomas committed
895

896 897 898
// When end marker arrives, we notify the client with buffer size = 0
// The client will likely call "delete tunnel"
// nevertheless we don't take the initiative
Laurent Thomas's avatar
Laurent Thomas committed
899 900 901 902 903
static int Gtpv1uHandleEndMarker(int h,
                                 uint8_t *msgBuf,
                                 uint32_t msgBufLen,
                                 uint16_t peerPort,
                                 uint32_t peerIp) {
904
  Gtpv1uMsgHeaderT      *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf;
905

906
  if ( msgHdr->version != 1 ||  msgHdr->PT != 1 ) {
907
    LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h);
908 909 910 911 912
    return GTPNOK;
  }

  pthread_mutex_lock(&globGtp.gtp_lock);
  // the socket Linux file handler is the instance id
913 914
  getInstRetInt(h);

915 916 917
  auto tunnel=inst->te2ue_mapping.find(ntohl(msgHdr->teid));

  if ( tunnel == inst->te2ue_mapping.end() ) {
918
    LOG_E(GTPU,"[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, msgHdr->teid);
919 920 921
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return GTPNOK;
  }
922

923 924 925 926 927 928 929
  // This context is not good for gtp
  // frame, ... has no meaning
  // manyother attributes may come from create tunnel
  protocol_ctxt_t ctxt;
  ctxt.module_id = 0;
  ctxt.enb_flag = 1;
  ctxt.instance = inst->addr.originInstance;
930
  ctxt.rntiMaybeUEid = tunnel->second.ue_id;
931 932 933 934 935
  ctxt.frame = 0;
  ctxt.subframe = 0;
  ctxt.eNB_index = 0;
  ctxt.brOption = 0;
  const srb_flag_t     srb_flag=SRB_FLAG_NO;
Laurent THOMAS's avatar
Laurent THOMAS committed
936
  const rb_id_t        rb_id=tunnel->second.incoming_rb_id;
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
  const mui_t          mui=RLC_MUI_UNDEFINED;
  const confirm_t      confirm=RLC_SDU_CONFIRM_NO;
  const pdcp_transmission_mode_t mode=PDCP_TRANSMISSION_MODE_DATA;
  const uint32_t sourceL2Id=0;
  const uint32_t destinationL2Id=0;
  pthread_mutex_unlock(&globGtp.gtp_lock);

  if ( !tunnel->second.callBack(&ctxt,
                                srb_flag,
                                rb_id,
                                mui,
                                confirm,
                                0,
                                NULL,
                                mode,
                                &sourceL2Id,
                                &destinationL2Id) )
954
    LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
955

956
  LOG_D(GTPU,"[%d] Received END marker packet for: teid:%x\n", h, ntohl(msgHdr->teid));
957
  return !GTPNOK;
Laurent Thomas's avatar
Laurent Thomas committed
958
}
959

Laurent Thomas's avatar
Laurent Thomas committed
960 961 962 963 964 965 966 967
static int Gtpv1uHandleGpdu(int h,
                            uint8_t *msgBuf,
                            uint32_t msgBufLen,
                            uint16_t peerPort,
                            uint32_t peerIp) {
  Gtpv1uMsgHeaderT      *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf;

  if ( msgHdr->version != 1 ||  msgHdr->PT != 1 ) {
968
    LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h);
Laurent Thomas's avatar
Laurent Thomas committed
969 970 971 972 973
    return GTPNOK;
  }

  pthread_mutex_lock(&globGtp.gtp_lock);
  // the socket Linux file handler is the instance id
974 975
  getInstRetInt(h);

Laurent Thomas's avatar
Laurent Thomas committed
976 977 978
  auto tunnel=inst->te2ue_mapping.find(ntohl(msgHdr->teid));

  if ( tunnel == inst->te2ue_mapping.end() ) {
979
    LOG_E(GTPU,"[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, ntohl(msgHdr->teid));
Laurent Thomas's avatar
Laurent Thomas committed
980 981 982 983
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return GTPNOK;
  }

984 985
  /* see TS 29.281 5.1 */
  //Minimum length of GTP-U header if non of the optional fields are present
986
  unsigned int offset = sizeof(Gtpv1uMsgHeaderT);
Laurent Thomas's avatar
Laurent Thomas committed
987

988
  uint8_t qfi = -1;
989
  bool rqi = false;
990
  uint32_t NR_PDCP_PDU_SN = 0;
991

992
  /* if E, S, or PN is set then there are 4 more bytes of header */
993
  if( msgHdr->E ||  msgHdr->S ||msgHdr->PN)
994 995 996 997 998 999 1000 1001 1002 1003
    offset += 4;

  if (msgHdr->E) {
    int next_extension_header_type = msgBuf[offset - 1];
    int extension_header_length;

    while (next_extension_header_type != NO_MORE_EXT_HDRS) {
      extension_header_length = msgBuf[offset];
      switch (next_extension_header_type) {
        case PDU_SESSION_CONTAINER: {
1004 1005 1006 1007
	  if (offset + sizeof(PDUSessionContainerT) > msgBufLen ) {
	    LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n");
	    return GTPNOK;
	  }
1008 1009
          PDUSessionContainerT *pdusession_cntr = (PDUSessionContainerT *)(msgBuf + offset + 1);
          qfi = pdusession_cntr->QFI;
1010
          rqi = pdusession_cntr->Reflective_QoS_activation;
1011 1012 1013
          break;
        }
        case NR_RAN_CONTAINER: {
1014 1015 1016 1017
	  if (offset + 1 > msgBufLen ) {
	    LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n");
	    return GTPNOK;
	  }
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
          uint8_t PDU_type = (msgBuf[offset+1]>>4) & 0x0f;
          if (PDU_type == 0){ //DL USER Data Format
            int additional_offset = 6; //Additional offset capturing the first non-mandatory octet (TS 38.425, Figure 5.5.2.1-1)
            if(msgBuf[offset+1]>>2 & 0x1){ //DL Discard Blocks flag is present
              LOG_I(GTPU, "DL User Data: DL Discard Blocks handling not enabled\n"); 
              additional_offset = additional_offset + 9; //For the moment ignore
            }
            if(msgBuf[offset+1]>>1 & 0x1){ //DL Flush flag is present
              LOG_I(GTPU, "DL User Data: DL Flush handling not enabled\n");
              additional_offset = additional_offset + 3; //For the moment ignore
            }
            if((msgBuf[offset+2]>>3)& 0x1){ //"Report delivered" enabled (TS 38.425, 5.4)
              /*Store the NR PDCP PDU SN for which a delivery status report shall be generated once the
               *PDU gets forwarded to the lower layers*/
              //NR_PDCP_PDU_SN = msgBuf[offset+6] << 16 | msgBuf[offset+7] << 8 | msgBuf[offset+8];
              NR_PDCP_PDU_SN = msgBuf[offset+additional_offset] << 16 | msgBuf[offset+additional_offset+1] << 8 | msgBuf[offset+additional_offset+2]; 
              LOG_D(GTPU, " NR_PDCP_PDU_SN: %u \n",  NR_PDCP_PDU_SN);
            }
1036
          }
1037 1038
          else{
            LOG_W(GTPU, "NR-RAN container type: %d not supported \n", PDU_type);
1039
          }
1040
          break;
1041
        }
1042 1043
        default:
          LOG_W(GTPU, "unhandled extension 0x%2.2x, skipping\n", next_extension_header_type);
1044
	  break;
1045
      }
Laurent Thomas's avatar
Laurent Thomas committed
1046

1047
      offset += extension_header_length * EXT_HDR_LNTH_OCTET_UNITS;
1048 1049 1050 1051
      if (offset > msgBufLen ) {
	LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n");
	return GTPNOK;
      }
1052
      next_extension_header_type = msgBuf[offset - 1];
1053 1054
    }
  }
Laurent Thomas's avatar
Laurent Thomas committed
1055 1056 1057 1058

  // This context is not good for gtp
  // frame, ... has no meaning
  // manyother attributes may come from create tunnel
Laurent Thomas's avatar
Laurent Thomas committed
1059
  protocol_ctxt_t ctxt;
Laurent Thomas's avatar
Laurent Thomas committed
1060 1061 1062
  ctxt.module_id = 0;
  ctxt.enb_flag = 1;
  ctxt.instance = inst->addr.originInstance;
1063
  ctxt.rntiMaybeUEid = tunnel->second.ue_id;
Laurent Thomas's avatar
Laurent Thomas committed
1064 1065 1066 1067 1068
  ctxt.frame = 0;
  ctxt.subframe = 0;
  ctxt.eNB_index = 0;
  ctxt.brOption = 0;
  const srb_flag_t     srb_flag=SRB_FLAG_NO;
Laurent THOMAS's avatar
Laurent THOMAS committed
1069
  const rb_id_t        rb_id=tunnel->second.incoming_rb_id;
Laurent Thomas's avatar
Laurent Thomas committed
1070 1071
  const mui_t          mui=RLC_MUI_UNDEFINED;
  const confirm_t      confirm=RLC_SDU_CONFIRM_NO;
1072
  const sdu_size_t sdu_buffer_size = msgBufLen - offset;
Laurent Thomas's avatar
Laurent Thomas committed
1073 1074 1075 1076
  unsigned char *const sdu_buffer=msgBuf+offset;
  const pdcp_transmission_mode_t mode=PDCP_TRANSMISSION_MODE_DATA;
  const uint32_t sourceL2Id=0;
  const uint32_t destinationL2Id=0;
Laurent Thomas's avatar
Laurent Thomas committed
1077
  pthread_mutex_unlock(&globGtp.gtp_lock);
Laurent Thomas's avatar
Laurent Thomas committed
1078

1079 1080
  if (sdu_buffer_size > 0) {
    if (qfi != -1 && tunnel->second.callBackSDAP) {
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
      if ( !tunnel->second.callBackSDAP(&ctxt,
                                        tunnel->second.ue_id,
                                        srb_flag,
                                        rb_id,
                                        mui,
                                        confirm,
                                        sdu_buffer_size,
                                        sdu_buffer,
                                        mode,
                                        &sourceL2Id,
                                        &destinationL2Id,
                                        qfi,
                                        rqi,
                                        tunnel->second.pdusession_id) )
        LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
1096
    } else {
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
      if ( !tunnel->second.callBack(&ctxt,
                                    srb_flag,
                                    rb_id,
                                    mui,
                                    confirm,
                                    sdu_buffer_size,
                                    sdu_buffer,
                                    mode,
                                    &sourceL2Id,
                                    &destinationL2Id) )
        LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
1108
    }
athanassopoulos's avatar
athanassopoulos committed
1109
  }
Laurent Thomas's avatar
Laurent Thomas committed
1110

1111 1112
  if(NR_PDCP_PDU_SN > 0 && NR_PDCP_PDU_SN %5 ==0){
    LOG_D (GTPU, "Create and send DL DATA Delivery status for the previously received PDU, NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN);
1113
    int rlc_tx_buffer_space = nr_rlc_get_available_tx_space(ctxt.rntiMaybeUEid, rb_id + 3);
1114
    LOG_D(GTPU, "Available buffer size in RLC for Tx: %d \n", rlc_tx_buffer_space);
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
    /*Total size of DDD_status PDU = 1 octet to report extension header length
     * size of mandatory part + 3 octets for highest transmitted/delivered PDCP SN
     * 1 octet for padding + 1 octet for next extension header type,
     * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/
    extensionHeader_t *extensionHeader;
    extensionHeader = (extensionHeader_t *) calloc(1, sizeof(extensionHeader_t)) ;
    extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1)/4;
    DlDataDeliveryStatus_flagsT DlDataDeliveryStatus;
    DlDataDeliveryStatus.deliveredPdcpSn = 0;
    DlDataDeliveryStatus.transmittedPdcpSn= 1; 
    DlDataDeliveryStatus.pduType = 1;
1126
    DlDataDeliveryStatus.drbBufferSize = htonl(rlc_tx_buffer_space); //htonl(10000000); //hardcoded for now but normally we should extract it from RLC
1127 1128 1129 1130 1131 1132
    memcpy(extensionHeader->buffer+1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT));
    uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT)+1;

    extensionHeader->buffer[offset] =   (NR_PDCP_PDU_SN >> 16) & 0xff;
    extensionHeader->buffer[offset+1] = (NR_PDCP_PDU_SN >> 8) & 0xff;
    extensionHeader->buffer[offset+2] = NR_PDCP_PDU_SN & 0xff;
1133 1134 1135 1136
    LOG_D(GTPU, "Octets reporting NR_PDCP_PDU_SN, extensionHeader-> %u:%u:%u \n",
          extensionHeader->buffer[offset],
          extensionHeader->buffer[offset+1],
          extensionHeader->buffer[offset+2]);
1137 1138 1139 1140 1141 1142 1143
    extensionHeader->buffer[offset+3] = 0x00; //Padding octet
    extensionHeader->buffer[offset+4] = 0x00; //No more extension headers
    /*Total size of DDD_status PDU = size of mandatory part +
     * 3 octets for highest transmitted/delivered PDCP SN +
     * 1 octet for padding + 1 octet for next extension header type,
     * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/
    extensionHeader->length  = 1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1;
1144
    gtpv1uCreateAndSendMsg(
1145 1146 1147 1148
        h, peerIp, peerPort, GTP_GPDU,
        inst->te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid,
        NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER,
        extensionHeader->buffer, extensionHeader->length);
1149
  }
Laurent Thomas's avatar
Laurent Thomas committed
1150

1151
  LOG_D(GTPU,"[%d] Received a %d bytes packet for: teid:%x\n", h,
Laurent Thomas's avatar
Laurent Thomas committed
1152 1153 1154 1155 1156 1157
        msgBufLen-offset,
        ntohl(msgHdr->teid));
  return !GTPNOK;
}

void gtpv1uReceiver(int h) {
1158
  uint8_t           udpData[65536];
Laurent Thomas's avatar
Laurent Thomas committed
1159 1160 1161 1162 1163 1164 1165
  int               udpDataLen;
  socklen_t          from_len;
  struct sockaddr_in addr;
  from_len = (socklen_t)sizeof(struct sockaddr_in);

  if ((udpDataLen = recvfrom(h, udpData, sizeof(udpData), 0,
                             (struct sockaddr *)&addr, &from_len)) < 0) {
1166
    LOG_E(GTPU, "[%d] Recvfrom failed (%s)\n", h, strerror(errno));
Laurent Thomas's avatar
Laurent Thomas committed
1167 1168
    return;
  } else if (udpDataLen == 0) {
1169
    LOG_W(GTPU, "[%d] Recvfrom returned 0\n", h);
Laurent Thomas's avatar
Laurent Thomas committed
1170 1171
    return;
  } else {
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
    if ( udpDataLen < (int)sizeof(Gtpv1uMsgHeaderT) ) {
      LOG_W(GTPU, "[%d] received malformed gtp packet \n", h);
      return;
    }
    Gtpv1uMsgHeaderT* msg=(Gtpv1uMsgHeaderT*) udpData;
    if ( (int)(ntohs(msg->msgLength) + sizeof(Gtpv1uMsgHeaderT)) != udpDataLen ) {
      LOG_W(GTPU, "[%d] received malformed gtp packet length\n", h);
      return;
    }
    LOG_D(GTPU, "[%d] Received GTP data, msg type: %x\n", h, msg->msgType);
    switch(msg->msgType) {
Laurent Thomas's avatar
Laurent Thomas committed
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
      case GTP_ECHO_RSP:
        break;

      case GTP_ECHO_REQ:
        Gtpv1uHandleEchoReq( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr);
        break;

      case GTP_ERROR_INDICATION:
        Gtpv1uHandleError( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr);
        break;
Laurent Thomas's avatar
Laurent Thomas committed
1193 1194

      case GTP_SUPPORTED_EXTENSION_HEADER_INDICATION:
Laurent Thomas's avatar
Laurent Thomas committed
1195
        Gtpv1uHandleSupportedExt( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr);
Laurent Thomas's avatar
Laurent Thomas committed
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
        break;

      case GTP_END_MARKER:
        Gtpv1uHandleEndMarker( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr);
        break;

      case GTP_GPDU:
        Gtpv1uHandleGpdu( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr);
        break;

      default:
1207
        LOG_E(GTPU, "[%d] Received a GTP packet of unknown type: %d\n", h, msg->msgType);
Laurent Thomas's avatar
Laurent Thomas committed
1208
        break;
Laurent Thomas's avatar
Laurent Thomas committed
1209 1210 1211 1212
    }
  }
}

Laurent Thomas's avatar
Laurent Thomas committed
1213 1214
#include <openair2/ENB_APP/enb_paramdef.h>

Laurent THOMAS's avatar
Laurent THOMAS committed
1215
void *gtpv1uTask(void *args)  {
Laurent Thomas's avatar
Laurent Thomas committed
1216 1217
  while(1) {
    /* Trying to fetch a message from the message queue.
1218 1219
       If the queue is empty, this function will block till a
       message is sent to the task.
Laurent Thomas's avatar
Laurent Thomas committed
1220 1221
    */
    MessageDef *message_p = NULL;
Laurent THOMAS's avatar
Laurent THOMAS committed
1222
    itti_receive_msg(TASK_GTPV1_U, &message_p);
Laurent Thomas's avatar
Laurent Thomas committed
1223 1224

    if (message_p != NULL ) {
Laurent Thomas's avatar
Laurent Thomas committed
1225 1226
      openAddr_t addr= {0};

Laurent Thomas's avatar
Laurent Thomas committed
1227 1228 1229
      switch (ITTI_MSG_ID(message_p)) {
        // DATA TO BE SENT TO UDP

1230 1231 1232
        case GTPV1U_TUNNEL_DATA_REQ: {
          gtpv1uSend(compatInst(ITTI_MSG_DESTINATION_INSTANCE(message_p)),
                      &GTPV1U_TUNNEL_DATA_REQ(message_p), false, false);
1233
        }
1234 1235
        break;

1236 1237 1238 1239 1240 1241
        case GTPV1U_DU_BUFFER_REPORT_REQ:{
          gtpv1uSendDlDeliveryStatus(compatInst(ITTI_MSG_DESTINATION_INSTANCE(message_p)),
              &GTPV1U_DU_BUFFER_REPORT_REQ(message_p));
        }
        break;

Laurent Thomas's avatar
Laurent Thomas committed
1242 1243 1244 1245 1246 1247
        case TERMINATE_MESSAGE:
          break;

        case TIMER_HAS_EXPIRED:
          LOG_E(GTPU, "Received unexpected timer expired (no need of timers in this version) %s\n", ITTI_MSG_NAME(message_p));
          break;
1248 1249 1250

        case GTPV1U_ENB_END_MARKER_REQ:
          gtpv1uEndTunnel(compatInst(ITTI_MSG_DESTINATION_INSTANCE(message_p)),
1251 1252
                          &GTPV1U_TUNNEL_DATA_REQ(message_p));
          itti_free(TASK_GTPV1_U, GTPV1U_TUNNEL_DATA_REQ(message_p).buffer);
1253 1254 1255
          break;

        case GTPV1U_ENB_DATA_FORWARDING_REQ:
Laurent Thomas's avatar
Laurent Thomas committed
1256 1257 1258 1259 1260 1261
        case GTPV1U_ENB_DATA_FORWARDING_IND:
        case GTPV1U_ENB_END_MARKER_IND:
          LOG_E(GTPU, "to be developped %s\n", ITTI_MSG_NAME(message_p));
          abort();
          break;

1262
        case GTPV1U_REQ:
Laurent THOMAS's avatar
Laurent THOMAS committed
1263
          // to be dev: should be removed, to use API
1264 1265
          strcpy(addr.originHost, GTPV1U_REQ(message_p).localAddrStr);
          strcpy(addr.originService, GTPV1U_REQ(message_p).localPortStr);
1266
          strcpy(addr.destinationService,addr.originService);
Laurent THOMAS's avatar
Laurent THOMAS committed
1267
          AssertFatal((legacyInstanceMapping=gtpv1Init(addr))!=0,"Instance 0 reserved for legacy\n");
Laurent THOMAS's avatar
Laurent THOMAS committed
1268 1269
          break;

Laurent Thomas's avatar
Laurent Thomas committed
1270 1271 1272
        default:
          LOG_E(GTPU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
          abort();
Laurent Thomas's avatar
Laurent Thomas committed
1273 1274 1275
          break;
      }

Laurent THOMAS's avatar
Laurent THOMAS committed
1276
      AssertFatal(EXIT_SUCCESS==itti_free(TASK_GTPV1_U, message_p), "Failed to free memory!\n");
Laurent Thomas's avatar
Laurent Thomas committed
1277 1278
    }

laurent's avatar
laurent committed
1279 1280
    struct epoll_event events[20];
    int nb_events = itti_get_events(TASK_GTPV1_U, events, 20);
Laurent Thomas's avatar
Laurent Thomas committed
1281

1282 1283
    for (int i = 0; i < nb_events; i++)
      if ((events[i].events&EPOLLIN))
Laurent Thomas's avatar
Laurent Thomas committed
1284 1285 1286 1287 1288 1289 1290 1291 1292
        gtpv1uReceiver(events[i].data.fd);
  }

  return NULL;
}

#ifdef __cplusplus
}
#endif