gtp_itf.cpp 49.6 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"
Laurent Thomas's avatar
Laurent Thomas committed
22 23 24 25 26 27 28 29 30 31 32 33 34
//#include <openair1/PHY/phy_extern.h>

#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 {
Laurent THOMAS's avatar
Laurent THOMAS committed
111
  map<int, gtpv1u_bearer_t> bearers;
112
  teid_t outgoing_teid;
Laurent Thomas's avatar
Laurent Thomas committed
113 114 115 116
} teidData_t;

typedef struct {
  rnti_t rnti;
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;
Laurent Thomas's avatar
Laurent Thomas committed
122 123 124 125 126
} rntiData_t;

class gtpEndPoint {
 public:
  openAddr_t addr;
Laurent Thomas's avatar
Laurent Thomas committed
127 128
  uint8_t foundAddr[20];
  int foundAddrLen;
129
  int ipVersion;
Laurent Thomas's avatar
Laurent Thomas committed
130 131
  map<int,teidData_t> ue2te_mapping;
  map<int,rntiData_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 144
};

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

  ~gtpEndPoints() {
    // automatically close all sockets on quit
148
    for (const auto &p : instances)
149 150
      close(p.first);
  }
Laurent Thomas's avatar
Laurent Thomas committed
151 152 153 154
};

gtpEndPoints globGtp;

155
// note TEid 0 is reserved for specific usage: echo req/resp, error and supported extensions
156
static  teid_t gtpv1uNewTeid(void) {
Laurent Thomas's avatar
Laurent Thomas committed
157 158 159 160 161 162 163 164
#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
}

165
instance_t legacyInstanceMapping=0;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
#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;


#define getRntiRetVoid(insT, RnTi)                                            \
    auto ptrRnti=insT->ue2te_mapping.find(RnTi);                        \
                                                                        \
  if (  ptrRnti==insT->ue2te_mapping.end() ) {                          \
    LOG_E(GTPU, "[%ld] gtpv1uSend failed: while getting ue rnti %x in hashtable ue_mapping\n", instance, rnti); \
    pthread_mutex_unlock(&globGtp.gtp_lock);                            \
    return;                                                             \
  }
195
  
196 197 198 199 200 201 202 203 204 205
#define getRntiRetInt(insT, RnTi)                                            \
    auto ptrRnti=insT->ue2te_mapping.find(RnTi);                        \
                                                                        \
  if (  ptrRnti==insT->ue2te_mapping.end() ) {                          \
    LOG_E(GTPU, "[%ld] gtpv1uSend failed: while getting ue rnti %x in hashtable ue_mapping\n", instance, rnti); \
    pthread_mutex_unlock(&globGtp.gtp_lock);                            \
    return GTPNOK;                                                             \
  }
  
#define HDR_MAX 256 // 256 is supposed to be larger than any gtp header
206 207 208 209 210 211 212 213 214 215 216 217 218 219
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) {
220
  LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid);
Laurent Thomas's avatar
Laurent Thomas committed
221

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

236
  curPtr+=sizeof(Gtpv1uMsgHeaderT);
237

238 239 240 241 242 243 244
  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++;
245 246
  }

247 248 249 250 251 252 253 254 255 256
  // 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");
257 258
    }
  }
259

260
  if (Msg!= NULL){
261 262
    memcpy(curPtr, Msg, msgLen);
    curPtr+=msgLen;
Laurent Thomas's avatar
Laurent Thomas committed
263 264
  }

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

275 276 277
  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
278 279 280 281 282 283 284 285 286
    return GTPNOK;
  }

  return  !GTPNOK;
}

static void gtpv1uSend(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) {
  uint8_t *buffer=req->buffer+req->offset;
  size_t length=req->length;
Laurent THOMAS's avatar
Laurent THOMAS committed
287
  rnti_t rnti=req->rnti;
Laurent Thomas's avatar
Laurent Thomas committed
288 289
  int  rab_id=req->rab_id;
  pthread_mutex_lock(&globGtp.gtp_lock);
290 291
  getInstRetVoid(compatInst(instance));
  getRntiRetVoid(inst, rnti);
Laurent Thomas's avatar
Laurent Thomas committed
292

Laurent THOMAS's avatar
Laurent THOMAS committed
293
  map<int, gtpv1u_bearer_t>::iterator ptr2=ptrRnti->second.bearers.find(rab_id);
Laurent Thomas's avatar
Laurent Thomas committed
294

295
  if ( ptr2 == ptrRnti->second.bearers.end() ) {
296
    LOG_E(GTPU,"[%ld] GTP-U instance: sending a packet to a non existant RNTI:RAB: %x/%x\n", instance, rnti, rab_id);
Laurent Thomas's avatar
Laurent Thomas committed
297 298
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
299 300
  }

301 302
  LOG_D(GTPU,"[%ld] sending a packet to RNTI:RAB:teid %x/%x/%x, len %lu, oldseq %d, oldnum %d\n",
        instance, rnti, rab_id,ptr2->second.teid_outgoing,length, ptr2->second.seqNum,ptr2->second.npduNum );
Laurent Thomas's avatar
Laurent Thomas committed
303 304

  if(seqNumFlag)
305
    ptr2->second.seqNum++;
Laurent Thomas's avatar
Laurent Thomas committed
306 307

  if(npduNumFlag)
308
    ptr2->second.npduNum++;
309

310
  // copy to release the mutex
Laurent THOMAS's avatar
Laurent THOMAS committed
311
  gtpv1u_bearer_t tmp=ptr2->second;
Laurent Thomas's avatar
Laurent Thomas committed
312
  pthread_mutex_unlock(&globGtp.gtp_lock);
313 314
  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);
Laurent Thomas's avatar
Laurent Thomas committed
315
}
316 317 318 319

static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) {
  uint8_t *buffer=req->buffer+req->offset;
  size_t length=req->length;
Laurent THOMAS's avatar
Laurent THOMAS committed
320
  rnti_t rnti=req->rnti;
321 322
  int  rab_id=req->pdusession_id;
  pthread_mutex_lock(&globGtp.gtp_lock);
323 324
  getInstRetVoid(compatInst(instance));
  getRntiRetVoid(inst, rnti);
325

Laurent THOMAS's avatar
Laurent THOMAS committed
326
  map<int, gtpv1u_bearer_t>::iterator ptr2=ptrRnti->second.bearers.find(rab_id);
327

328
  if ( ptr2 == ptrRnti->second.bearers.end() ) {
329
    LOG_D(GTPU,"GTP-U instance: %ld sending a packet to a non existant RNTI:RAB: %x/%x\n", instance, rnti, rab_id);
330 331
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
332 333
  }

334
  LOG_D(GTPU,"[%ld] GTP-U sending a packet to RNTI:RAB:teid %x/%x/%x, len %lu, oldseq %d, oldnum %d\n",
335
        instance, rnti, rab_id,ptr2->second.teid_outgoing,length, ptr2->second.seqNum,ptr2->second.npduNum );
336 337

  if(seqNumFlag)
338
    ptr2->second.seqNum++;
339 340

  if(npduNumFlag)
341
    ptr2->second.npduNum++;
342

343
  // copy to release the mutex
Laurent THOMAS's avatar
Laurent THOMAS committed
344
  gtpv1u_bearer_t tmp=ptr2->second;
345
  pthread_mutex_unlock(&globGtp.gtp_lock);
346 347 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

  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);
  }
375 376
}

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
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){
  rnti_t rnti=req->rnti;
  int  rab_id=req->pdusession_id;
  pthread_mutex_lock(&globGtp.gtp_lock);
410 411
  getInstRetVoid(compatInst(instance));
  getRntiRetVoid(inst, rnti);
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429

  map<int, gtpv1u_bearer_t>::iterator ptr2=ptrRnti->second.bearers.find(rab_id);

  if ( ptr2 == ptrRnti->second.bearers.end() ) {
    LOG_D(GTPU,"GTP-U instance: %ld sending a packet to a non existant RNTI:RAB: %x/%x\n", instance, rnti, rab_id);
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
  }

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

  LOG_I(GTPU,"[%ld] GTP-U sending DL Data Delivery status to RNTI:RAB:teid %x/%x/%x, oldseq %d, oldnum %d\n",
        instance, rnti, rab_id,ptr2->second.teid_outgoing, ptr2->second.seqNum,ptr2->second.npduNum );
  // copy to release the mutex
  gtpv1u_bearer_t tmp=ptr2->second;
  pthread_mutex_unlock(&globGtp.gtp_lock);
430 431
  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);
432 433
}

434
static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req) {
Laurent THOMAS's avatar
Laurent THOMAS committed
435
  rnti_t rnti=req->rnti;
436 437
  int  rab_id=req->rab_id;
  pthread_mutex_lock(&globGtp.gtp_lock);
438 439
  getInstRetVoid(compatInst(instance));
  getRntiRetVoid(inst, rnti);
440

Laurent THOMAS's avatar
Laurent THOMAS committed
441
  map<int, gtpv1u_bearer_t>::iterator ptr2=ptrRnti->second.bearers.find(rab_id);
442

443
  if ( ptr2 == ptrRnti->second.bearers.end() ) {
444
    LOG_E(GTPU,"[%ld] GTP-U sending a packet to a non existant RNTI:RAB: %x/%x\n", instance, rnti, rab_id);
445 446
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
447
  }
448

449 450
  LOG_D(GTPU,"[%ld] sending a end packet packet to RNTI:RAB:teid %x/%x/%x\n",
        instance, rnti, rab_id,ptr2->second.teid_outgoing);
Laurent THOMAS's avatar
Laurent THOMAS committed
451
  gtpv1u_bearer_t tmp=ptr2->second;
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
  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
470
  char ip4[INET_ADDRSTRLEN];
Laurent THOMAS's avatar
Laurent THOMAS committed
471
  //char ip6[INET6_ADDRSTRLEN];
472
  LOG_D(GTPU,"[%ld] sending end packet to %s\n", instance, inet_ntoa(to.sin_addr) );
Laurent Thomas's avatar
Laurent Thomas committed
473

474 475
  if (sendto(compatInst(instance), (void *)&msgHdr, sizeof(msgHdr), 0,(struct sockaddr *)&to, sizeof(to) ) !=  sizeof(msgHdr)) {
    LOG_E(GTPU,
476
          "[%ld] Failed to send data to %s on port %d, buffer size %lu\n",
Laurent THOMAS's avatar
Laurent THOMAS committed
477
          compatInst(instance), inet_ntop(AF_INET, &tmp.outgoing_ip_addr, ip4, INET_ADDRSTRLEN), tmp.outgoing_port, sizeof(msgHdr));
478 479
  }
}
480

Laurent Thomas's avatar
Laurent Thomas committed
481 482 483 484 485 486 487 488 489 490 491 492
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
493

Laurent Thomas's avatar
Laurent Thomas committed
494 495 496 497 498 499 500 501 502 503 504 505 506 507
  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
508 509 510
    } else {
      // We create the gtp instance on the socket
      globGtp.instances[sockfd].addr=addr;
511 512 513 514 515 516

      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);
517
        globGtp.instances[sockfd].ipVersion=4;
518 519 520 521 522 523 524
        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);
525
        globGtp.instances[sockfd].ipVersion=6;
526 527
      } else
        AssertFatal(false,"Local address is not IPv4 or IPv6");
Laurent Thomas's avatar
Laurent Thomas committed
528 529 530 531 532 533 534 535 536 537 538 539
    }

    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
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561

  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
562 563
  int sendbuff = 1000*1000*10;
  AssertFatal(0==setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)),"");
564
  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
565 566 567
  return sockfd;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
568
instance_t gtpv1Init(openAddr_t context) {
Laurent Thomas's avatar
Laurent Thomas committed
569 570 571 572
  pthread_mutex_lock(&globGtp.gtp_lock);
  int id=udpServerSocket(context);

  if (id>=0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
573
    itti_subscribe_event_fd(TASK_GTPV1_U, id);
Laurent Thomas's avatar
Laurent Thomas committed
574 575 576 577
  } else
    LOG_E(GTPU,"can't create GTP-U instance\n");

  pthread_mutex_unlock(&globGtp.gtp_lock);
578
  LOG_I(GTPU, "Created gtpu instance id: %d\n", id);
Laurent Thomas's avatar
Laurent Thomas committed
579 580 581
  return id;
}

582 583
void GtpuUpdateTunnelOutgoingTeid(instance_t instance, rnti_t rnti, ebi_t bearer_id, teid_t newOutgoingTeid) {
  pthread_mutex_lock(&globGtp.gtp_lock);
584 585
  getInstRetVoid(compatInst(instance));
  getRntiRetVoid(inst, rnti);
586

Laurent THOMAS's avatar
Laurent THOMAS committed
587
  map<int, gtpv1u_bearer_t>::iterator ptr2=ptrRnti->second.bearers.find(bearer_id);
588 589

  if ( ptr2 == ptrRnti->second.bearers.end() ) {
590
    LOG_E(GTPU,"[%ld] Update tunnel for a existing rnti %x, but wrong bearer_id %u\n", instance, rnti, bearer_id);
591 592
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return;
593 594 595
  }

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

601 602 603 604 605 606 607 608 609 610
teid_t newGtpuCreateTunnel(instance_t instance,
                           rnti_t rnti,
                           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
611
  pthread_mutex_lock(&globGtp.gtp_lock);
612
  getInstRetInt(compatInst(instance));
Laurent Thomas's avatar
Laurent Thomas committed
613
  auto it=inst->ue2te_mapping.find(rnti);
Laurent Thomas's avatar
Laurent Thomas committed
614

615
  if ( it != inst->ue2te_mapping.end() &&  it->second.bearers.find(outgoing_bearer_id) != it->second.bearers.end()) {
616
    LOG_W(GTPU,"[%ld] Create a config for a already existing GTP tunnel (rnti %x)\n", instance, rnti);
Laurent Thomas's avatar
Laurent Thomas committed
617 618 619
    inst->ue2te_mapping.erase(it);
  }

620
  teid_t incoming_teid=gtpv1uNewTeid();
Laurent Thomas's avatar
Laurent Thomas committed
621

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

Laurent THOMAS's avatar
Laurent THOMAS committed
627
  inst->te2ue_mapping[incoming_teid].rnti=rnti;
Laurent Thomas's avatar
Laurent Thomas committed
628

629
  inst->te2ue_mapping[incoming_teid].incoming_rb_id= incoming_bearer_id;
630

631 632
  inst->te2ue_mapping[incoming_teid].outgoing_teid= outgoing_teid;

Laurent THOMAS's avatar
Laurent THOMAS committed
633
  inst->te2ue_mapping[incoming_teid].callBack=callBack;
634 635

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

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

Laurent THOMAS's avatar
Laurent THOMAS committed
639
  gtpv1u_bearer_t *tmp=&inst->ue2te_mapping[rnti].bearers[outgoing_bearer_id];
Laurent Thomas's avatar
Laurent Thomas committed
640

Laurent Thomas's avatar
Laurent Thomas committed
641
  int addrs_length_in_bytes = remoteAddr.length / 8;
Laurent Thomas's avatar
Laurent Thomas committed
642

Laurent Thomas's avatar
Laurent Thomas committed
643 644 645 646
  switch (addrs_length_in_bytes) {
    case 4:
      memcpy(&tmp->outgoing_ip_addr,remoteAddr.buffer,4);
      break;
Laurent Thomas's avatar
Laurent Thomas committed
647

Laurent Thomas's avatar
Laurent Thomas committed
648 649 650 651
    case 16:
      memcpy(tmp->outgoing_ip6_addr.s6_addr,remoteAddr.buffer,
             16);
      break;
Laurent Thomas's avatar
Laurent Thomas committed
652

Laurent Thomas's avatar
Laurent Thomas committed
653 654 655 656 657 658 659 660 661
    case 20:
      memcpy(&tmp->outgoing_ip_addr,remoteAddr.buffer,4);
      memcpy(&tmp->outgoing_ip6_addr.s6_addr,
             remoteAddr.buffer+4,
             16);

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

Laurent THOMAS's avatar
Laurent THOMAS committed
663
  tmp->teid_incoming = incoming_teid;
Laurent Thomas's avatar
Laurent Thomas committed
664
  tmp->outgoing_port=port;
Laurent THOMAS's avatar
Laurent THOMAS committed
665
  tmp->teid_outgoing= outgoing_teid;
666
  tmp->outgoing_qfi=outgoing_qfi;
Laurent Thomas's avatar
Laurent Thomas committed
667
  pthread_mutex_unlock(&globGtp.gtp_lock);
668 669
  char ip4[INET_ADDRSTRLEN];
  char ip6[INET6_ADDRSTRLEN];
Laurent THOMAS's avatar
Laurent THOMAS committed
670
  LOG_I(GTPU, "[%ld] Created tunnel for RNTI %x, teid for DL: %x, teid for UL %x to remote IPv4: %s, IPv6 %s\n",
Laurent Thomas's avatar
Laurent Thomas committed
671
        instance,
Laurent THOMAS's avatar
Laurent THOMAS committed
672
        rnti,
Laurent THOMAS's avatar
Laurent THOMAS committed
673
        tmp->teid_incoming,
674
        tmp->teid_outgoing,
675 676
        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
677
  return incoming_teid;
Laurent Thomas's avatar
Laurent Thomas committed
678 679
}

Laurent THOMAS's avatar
Laurent THOMAS committed
680
int gtpv1u_create_s1u_tunnel(instance_t instance,
Laurent THOMAS's avatar
Laurent THOMAS committed
681 682
                             const gtpv1u_enb_create_tunnel_req_t  *create_tunnel_req,
                             gtpv1u_enb_create_tunnel_resp_t *create_tunnel_resp) {
683
  LOG_D(GTPU, "[%ld] Start create tunnels for RNTI %x, num_tunnels %d, sgw_S1u_teid %x\n",
Laurent Thomas's avatar
Laurent Thomas committed
684
        instance,
Laurent Thomas's avatar
Laurent Thomas committed
685 686 687
        create_tunnel_req->rnti,
        create_tunnel_req->num_tunnels,
        create_tunnel_req->sgw_S1u_teid[0]);
688 689 690 691 692 693 694 695
  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
696
  for (int i = 0; i < create_tunnel_req->num_tunnels; i++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
697 698 699 700
    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;
701 702 703 704 705 706 707 708 709 710
    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
711 712 713
    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
714
    create_tunnel_resp->enb_S1u_teid[i]=teid;
Laurent Thomas's avatar
Laurent Thomas committed
715
    create_tunnel_resp->eps_bearer_id[i] = create_tunnel_req->eps_bearer_id[i];
716 717
    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
718 719 720 721 722
  }

  return !GTPNOK;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
723
int gtpv1u_update_s1u_tunnel(
Laurent Thomas's avatar
Laurent Thomas committed
724 725 726 727
  const instance_t                              instance,
  const gtpv1u_enb_create_tunnel_req_t *const  create_tunnel_req,
  const rnti_t                                  prior_rnti
) {
728
  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
729
        instance,
Laurent Thomas's avatar
Laurent Thomas committed
730 731 732 733 734 735
        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);
736
  getInstRetInt(compatInst(instance));
Laurent Thomas's avatar
Laurent Thomas committed
737

738
  if ( inst->ue2te_mapping.find(create_tunnel_req->rnti) == inst->ue2te_mapping.end() ) {
739 740
    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
741 742 743 744 745
  }

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

  if ( it != inst->ue2te_mapping.end() ) {
746
    LOG_W(GTPU,"[%ld] Update a not existing tunnel, start create the new one (new rnti %x, old rnti %x)\n", instance, create_tunnel_req->rnti, prior_rnti);
Laurent Thomas's avatar
Laurent Thomas committed
747
    pthread_mutex_unlock(&globGtp.gtp_lock);
Laurent Thomas's avatar
Laurent Thomas committed
748
    gtpv1u_enb_create_tunnel_resp_t tmp;
Laurent THOMAS's avatar
Laurent THOMAS committed
749
    (void)gtpv1u_create_s1u_tunnel(instance, create_tunnel_req, &tmp);
Laurent Thomas's avatar
Laurent Thomas committed
750 751 752 753 754 755 756 757
    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
758

759 760 761
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) {
762
  LOG_D(GTPU, "[%ld] Start create tunnels for RNTI %x, num_tunnels %d, sgw_S1u_teid %x\n",
Laurent Thomas's avatar
Laurent Thomas committed
763
        instance,
764 765
        create_tunnel_req->rnti,
        create_tunnel_req->num_tunnels,
766
        create_tunnel_req->outgoing_teid[0]);
767 768 769 770 771 772 773
  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);
774
  for (int i = 0; i < create_tunnel_req->num_tunnels; i++) {
775 776 777 778 779 780 781 782 783 784
    teid_t teid = newGtpuCreateTunnel(instance,
                                      create_tunnel_req->rnti,
                                      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);
785 786 787 788
    create_tunnel_resp->status=0;
    create_tunnel_resp->rnti=create_tunnel_req->rnti;
    create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels;
    create_tunnel_resp->gnb_NGu_teid[i]=teid;
789 790
    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
791 792
  }

793 794 795 796 797 798 799 800
  return !GTPNOK;
}

int gtpv1u_update_ngu_tunnel(
  const instance_t instanceP,
  const gtpv1u_gnb_create_tunnel_req_t *const  create_tunnel_req_pP,
  const rnti_t prior_rnti
) {
Laurent THOMAS's avatar
Laurent THOMAS committed
801
  AssertFatal( false, "to be developped\n");
802 803 804
  return GTPNOK;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
805
int gtpv1u_create_x2u_tunnel(
Laurent Thomas's avatar
Laurent Thomas committed
806
  const instance_t instanceP,
Laurent Thomas's avatar
Laurent Thomas committed
807 808
  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
809 810
  AssertFatal( false, "to be developped\n");
}
Laurent Thomas's avatar
Laurent Thomas committed
811

Laurent THOMAS's avatar
Laurent THOMAS committed
812
int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) {
813 814
  LOG_D(GTPU, "[%ld] Start delete tunnels for RNTI %x\n",
        instance, rnti);
Laurent Thomas's avatar
Laurent Thomas committed
815
  pthread_mutex_lock(&globGtp.gtp_lock);
816 817
  getInstRetInt(compatInst(instance));
  getRntiRetInt(inst, rnti);
Laurent Thomas's avatar
Laurent Thomas committed
818

Laurent THOMAS's avatar
Laurent THOMAS committed
819 820
  int nb=0;

821 822
  for (auto j=ptrRnti->second.bearers.begin();
       j!=ptrRnti->second.bearers.end();
Laurent THOMAS's avatar
Laurent THOMAS committed
823
       ++j) {
Laurent Thomas's avatar
Laurent Thomas committed
824
    inst->te2ue_mapping.erase(j->second.teid_incoming);
Laurent THOMAS's avatar
Laurent THOMAS committed
825 826
    nb++;
  }
Laurent Thomas's avatar
Laurent Thomas committed
827

828
  inst->ue2te_mapping.erase(ptrRnti);
Laurent Thomas's avatar
Laurent Thomas committed
829
  pthread_mutex_unlock(&globGtp.gtp_lock);
830
  LOG_I(GTPU, "[%ld] Deleted all tunnels for RNTI %x (%d tunnels deleted)\n", instance, rnti, nb);
Laurent Thomas's avatar
Laurent Thomas committed
831 832 833
  return !GTPNOK;
}

834 835
// Legacy delete tunnel finish by deleting all the rnti
// so the list of bearer provided is only a design bug
Laurent THOMAS's avatar
Laurent THOMAS committed
836 837
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
838
  return  newGtpuDeleteAllTunnels(instance, req_pP->rnti);
839
}
Laurent THOMAS's avatar
Laurent THOMAS committed
840 841

int newGtpuDeleteTunnels(instance_t instance, rnti_t rnti, int nbTunnels, pdusessionid_t *pdusession_id) {
Laurent THOMAS's avatar
Laurent THOMAS committed
842 843 844
  LOG_D(GTPU, "[%ld] Start delete tunnels for RNTI %x\n",
        instance, rnti);
  pthread_mutex_lock(&globGtp.gtp_lock);
845 846
  getInstRetInt(compatInst(instance));
  getRntiRetInt(inst, rnti);
Laurent THOMAS's avatar
Laurent THOMAS committed
847
  int nb=0;
848

Laurent THOMAS's avatar
Laurent THOMAS committed
849
  for (int i=0; i<nbTunnels; i++) {
850
    auto ptr2=ptrRnti->second.bearers.find(pdusession_id[i]);
Laurent THOMAS's avatar
Laurent THOMAS committed
851

852
    if ( ptr2 == ptrRnti->second.bearers.end() ) {
Laurent THOMAS's avatar
Laurent THOMAS committed
853 854 855 856 857 858
      LOG_E(GTPU,"[%ld] GTP-U instance: delete of not existing tunnel RNTI:RAB: %x/%x\n", instance, rnti,pdusession_id[i]);
    } else {
      inst->te2ue_mapping.erase(ptr2->second.teid_incoming);
      nb++;
    }
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
859

860
  if (ptrRnti->second.bearers.size() == 0 )
Laurent THOMAS's avatar
Laurent THOMAS committed
861
    // no tunnels on this rnti, erase the ue entry
862
    inst->ue2te_mapping.erase(ptrRnti);
Laurent THOMAS's avatar
Laurent THOMAS committed
863

Laurent THOMAS's avatar
Laurent THOMAS committed
864 865 866
  pthread_mutex_unlock(&globGtp.gtp_lock);
  LOG_I(GTPU, "[%ld] Deleted all tunnels for RNTI %x (%d tunnels deleted)\n", instance, rnti, nb);
  return !GTPNOK;
867 868
}

869
int gtpv1u_delete_x2u_tunnel( const instance_t instanceP,
Laurent THOMAS's avatar
Laurent THOMAS committed
870 871
                              const gtpv1u_enb_delete_tunnel_req_t *const req_pP) {
  LOG_E(GTPU,"x2 tunnel not implemented\n");
872
  return 0;
Laurent THOMAS's avatar
Laurent THOMAS committed
873 874
}

Laurent THOMAS's avatar
Laurent THOMAS committed
875
int gtpv1u_delete_ngu_tunnel( const instance_t instance,
Laurent THOMAS's avatar
Laurent THOMAS committed
876
                              gtpv1u_gnb_delete_tunnel_req_t *req) {
Laurent THOMAS's avatar
Laurent THOMAS committed
877 878
  return  newGtpuDeleteTunnels(instance, req->rnti, req->num_pdusession, req->pdusession_id);
}
Laurent THOMAS's avatar
Laurent THOMAS committed
879

Laurent Thomas's avatar
Laurent Thomas committed
880 881 882 883 884
static int Gtpv1uHandleEchoReq(int h,
                               uint8_t *msgBuf,
                               uint32_t msgBufLen,
                               uint16_t peerPort,
                               uint32_t peerIp) {
885
  Gtpv1uMsgHeaderT      *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf;
Laurent THOMAS's avatar
Laurent THOMAS committed
886

887 888 889 890 891 892 893 894 895 896
  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
897
  uint16_t seq=ntohs(*(uint16_t *)(msgHdr+1));
898
  LOG_D(GTPU, "[%d] Received a echo request, TEID: %d, seq: %hu\n", h, msgHdr->teid, seq);
Laurent THOMAS's avatar
Laurent THOMAS committed
899
  uint8_t recovery[2]= {14,0};
900
  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
901 902 903 904 905 906 907
}

static int Gtpv1uHandleError(int h,
                             uint8_t *msgBuf,
                             uint32_t msgBufLen,
                             uint16_t peerPort,
                             uint32_t peerIp) {
908
  LOG_E(GTPU,"Hadle error to be dev\n");
Laurent Thomas's avatar
Laurent Thomas committed
909 910 911
  int rc = GTPNOK;
  return rc;
}
Laurent Thomas's avatar
Laurent Thomas committed
912

Laurent Thomas's avatar
Laurent Thomas committed
913
static int Gtpv1uHandleSupportedExt(int h,
Laurent Thomas's avatar
Laurent Thomas committed
914 915 916 917
                                    uint8_t *msgBuf,
                                    uint32_t msgBufLen,
                                    uint16_t peerPort,
                                    uint32_t peerIp) {
918
  LOG_E(GTPU,"Supported extensions to be dev\n");
Laurent Thomas's avatar
Laurent Thomas committed
919 920 921
  int rc = GTPNOK;
  return rc;
}
Laurent Thomas's avatar
Laurent Thomas committed
922

923 924 925
// 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
926 927 928 929 930
static int Gtpv1uHandleEndMarker(int h,
                                 uint8_t *msgBuf,
                                 uint32_t msgBufLen,
                                 uint16_t peerPort,
                                 uint32_t peerIp) {
931
  Gtpv1uMsgHeaderT      *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf;
932

933
  if ( msgHdr->version != 1 ||  msgHdr->PT != 1 ) {
934
    LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h);
935 936 937 938 939
    return GTPNOK;
  }

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

942 943 944
  auto tunnel=inst->te2ue_mapping.find(ntohl(msgHdr->teid));

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

950 951 952 953 954 955 956 957 958 959 960 961 962
  // 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;
  ctxt.rnti = tunnel->second.rnti;
  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
963
  const rb_id_t        rb_id=tunnel->second.incoming_rb_id;
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
  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) )
981
    LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
982

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

Laurent Thomas's avatar
Laurent Thomas committed
987 988 989 990 991 992 993 994
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 ) {
995
    LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h);
Laurent Thomas's avatar
Laurent Thomas committed
996 997 998 999 1000
    return GTPNOK;
  }

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

Laurent Thomas's avatar
Laurent Thomas committed
1003 1004 1005
  auto tunnel=inst->te2ue_mapping.find(ntohl(msgHdr->teid));

  if ( tunnel == inst->te2ue_mapping.end() ) {
1006
    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
1007 1008 1009 1010
    pthread_mutex_unlock(&globGtp.gtp_lock);
    return GTPNOK;
  }

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

1015
  uint8_t qfi = -1;
1016
  bool rqi = false;
1017
  uint32_t NR_PDCP_PDU_SN = 0;
1018

1019
  /* if E, S, or PN is set then there are 4 more bytes of header */
1020
  if( msgHdr->E ||  msgHdr->S ||msgHdr->PN)
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
    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: {
1031 1032 1033 1034
	  if (offset + sizeof(PDUSessionContainerT) > msgBufLen ) {
	    LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n");
	    return GTPNOK;
	  }
1035 1036
          PDUSessionContainerT *pdusession_cntr = (PDUSessionContainerT *)(msgBuf + offset + 1);
          qfi = pdusession_cntr->QFI;
1037
          rqi = pdusession_cntr->Reflective_QoS_activation;
1038 1039 1040
          break;
        }
        case NR_RAN_CONTAINER: {
1041 1042 1043 1044
	  if (offset + 1 > msgBufLen ) {
	    LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n");
	    return GTPNOK;
	  }
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
          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);
            }
1063
          }
1064 1065
          else{
            LOG_W(GTPU, "NR-RAN container type: %d not supported \n", PDU_type);
1066
          }
1067
          break;
1068
        }
1069 1070
        default:
          LOG_W(GTPU, "unhandled extension 0x%2.2x, skipping\n", next_extension_header_type);
1071
	  break;
1072
      }
Laurent Thomas's avatar
Laurent Thomas committed
1073

1074
      offset += extension_header_length * EXT_HDR_LNTH_OCTET_UNITS;
1075 1076 1077 1078
      if (offset > msgBufLen ) {
	LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n");
	return GTPNOK;
      }
1079
      next_extension_header_type = msgBuf[offset - 1];
1080 1081
    }
  }
Laurent Thomas's avatar
Laurent Thomas committed
1082 1083 1084 1085

  // 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
1086
  protocol_ctxt_t ctxt;
Laurent Thomas's avatar
Laurent Thomas committed
1087 1088 1089 1090 1091 1092 1093 1094 1095
  ctxt.module_id = 0;
  ctxt.enb_flag = 1;
  ctxt.instance = inst->addr.originInstance;
  ctxt.rnti = tunnel->second.rnti;
  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
1096
  const rb_id_t        rb_id=tunnel->second.incoming_rb_id;
Laurent Thomas's avatar
Laurent Thomas committed
1097 1098
  const mui_t          mui=RLC_MUI_UNDEFINED;
  const confirm_t      confirm=RLC_SDU_CONFIRM_NO;
1099
  const sdu_size_t sdu_buffer_size = msgBufLen - offset;
Laurent Thomas's avatar
Laurent Thomas committed
1100 1101 1102 1103
  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
1104
  pthread_mutex_unlock(&globGtp.gtp_lock);
Laurent Thomas's avatar
Laurent Thomas committed
1105

1106 1107 1108 1109 1110 1111 1112 1113
  if (sdu_buffer_size > 0) {
    if (qfi != -1 && tunnel->second.callBackSDAP) {
      if (!tunnel->second.callBackSDAP(&ctxt, 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);
    } else {
      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);
    }
athanassopoulos's avatar
athanassopoulos committed
1114
  }
Laurent Thomas's avatar
Laurent Thomas committed
1115

1116 1117
  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);
1118
    int rlc_tx_buffer_space = nr_rlc_get_available_tx_space(ctxt.rnti, rb_id + 3);
1119
    LOG_D(GTPU, "Available buffer size in RLC for Tx: %d \n", rlc_tx_buffer_space);
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
    /*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;
1131
    DlDataDeliveryStatus.drbBufferSize = htonl(rlc_tx_buffer_space); //htonl(10000000); //hardcoded for now but normally we should extract it from RLC
1132 1133 1134 1135 1136 1137
    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;
1138 1139 1140 1141
    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]);
1142 1143 1144 1145 1146 1147 1148
    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;
1149
    gtpv1uCreateAndSendMsg(
1150 1151 1152 1153
        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);
1154
  }
Laurent Thomas's avatar
Laurent Thomas committed
1155

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

void gtpv1uReceiver(int h) {
1163
  uint8_t           udpData[65536];
Laurent Thomas's avatar
Laurent Thomas committed
1164 1165 1166 1167 1168 1169 1170
  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) {
1171
    LOG_E(GTPU, "[%d] Recvfrom failed (%s)\n", h, strerror(errno));
Laurent Thomas's avatar
Laurent Thomas committed
1172 1173
    return;
  } else if (udpDataLen == 0) {
1174
    LOG_W(GTPU, "[%d] Recvfrom returned 0\n", h);
Laurent Thomas's avatar
Laurent Thomas committed
1175 1176
    return;
  } else {
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
    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
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
      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
1198 1199

      case GTP_SUPPORTED_EXTENSION_HEADER_INDICATION:
Laurent Thomas's avatar
Laurent Thomas committed
1200
        Gtpv1uHandleSupportedExt( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr);
Laurent Thomas's avatar
Laurent Thomas committed
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
        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:
1212
        LOG_E(GTPU, "[%d] Received a GTP packet of unknown type: %d\n", h, msg->msgType);
Laurent Thomas's avatar
Laurent Thomas committed
1213
        break;
Laurent Thomas's avatar
Laurent Thomas committed
1214 1215 1216 1217
    }
  }
}

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

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

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

Laurent Thomas's avatar
Laurent Thomas committed
1232 1233 1234
      switch (ITTI_MSG_ID(message_p)) {
        // DATA TO BE SENT TO UDP
        case GTPV1U_ENB_TUNNEL_DATA_REQ: {
1235
          gtpv1uSend(compatInst(ITTI_MSG_DESTINATION_INSTANCE(message_p)),
Laurent Thomas's avatar
Laurent Thomas committed
1236
                     &GTPV1U_ENB_TUNNEL_DATA_REQ(message_p), false, false);
Laurent THOMAS's avatar
Laurent THOMAS committed
1237
          itti_free(TASK_GTPV1_U, GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).buffer);
Laurent Thomas's avatar
Laurent Thomas committed
1238 1239 1240
        }
        break;

1241 1242 1243
        case GTPV1U_GNB_TUNNEL_DATA_REQ: {
          gtpv1uSend2(compatInst(ITTI_MSG_DESTINATION_INSTANCE(message_p)),
                      &GTPV1U_GNB_TUNNEL_DATA_REQ(message_p), false, false);
1244
        }
1245 1246
        break;

1247 1248 1249 1250 1251 1252
        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
1253 1254 1255 1256 1257 1258
        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;
1259 1260 1261 1262

        case GTPV1U_ENB_END_MARKER_REQ:
          gtpv1uEndTunnel(compatInst(ITTI_MSG_DESTINATION_INSTANCE(message_p)),
                          &GTPV1U_ENB_TUNNEL_DATA_REQ(message_p));
Laurent THOMAS's avatar
Laurent THOMAS committed
1263
          itti_free(TASK_GTPV1_U, GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).buffer);
1264 1265 1266
          break;

        case GTPV1U_ENB_DATA_FORWARDING_REQ:
Laurent Thomas's avatar
Laurent Thomas committed
1267 1268 1269 1270 1271 1272
        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;

1273
        case GTPV1U_REQ:
Laurent THOMAS's avatar
Laurent THOMAS committed
1274
          // to be dev: should be removed, to use API
1275 1276
          strcpy(addr.originHost, GTPV1U_REQ(message_p).localAddrStr);
          strcpy(addr.originService, GTPV1U_REQ(message_p).localPortStr);
1277
          strcpy(addr.destinationService,addr.originService);
Laurent THOMAS's avatar
Laurent THOMAS committed
1278
          AssertFatal((legacyInstanceMapping=gtpv1Init(addr))!=0,"Instance 0 reserved for legacy\n");
Laurent THOMAS's avatar
Laurent THOMAS committed
1279 1280
          break;

Laurent Thomas's avatar
Laurent Thomas committed
1281 1282 1283
        default:
          LOG_E(GTPU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
          abort();
Laurent Thomas's avatar
Laurent Thomas committed
1284 1285 1286
          break;
      }

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

laurent's avatar
laurent committed
1290 1291
    struct epoll_event events[20];
    int nb_events = itti_get_events(TASK_GTPV1_U, events, 20);
Laurent Thomas's avatar
Laurent Thomas committed
1292

1293 1294
    for (int i = 0; i < nb_events; i++)
      if ((events[i].events&EPOLLIN))
Laurent Thomas's avatar
Laurent Thomas committed
1295 1296 1297 1298 1299 1300 1301 1302 1303
        gtpv1uReceiver(events[i].data.fd);
  }

  return NULL;
}

#ifdef __cplusplus
}
#endif