probe.c 17.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/* mac_lte_logger.c
 *
 * Example code for sending MAC LTE frames over UDP
 * Written by Martin Mathieson, with input from Kiran Kumar
 * This header file may also be distributed under
 * the terms of the BSD Licence as follows:
 *
 * Copyright (C) 2009 Martin Mathieson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE
 */

/*! \file probe.c
* \brief
* \author navid nikaein
* \date 2010-2012
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
/** @defgroup _oai System definitions
There is different modules:
- OAI Address
- OAI Components
- \ref _frame

numbering:
-# OAI Address
-# OAI Components
-# \ref _frame

The following diagram is based on graphviz (http://www.graphviz.org/), you need to install the package to view the diagram.
 *
 * \dot
 * digraph group_frame  {
 *     node [shape=rect, fontname=Helvetica, fontsize=8,style=filled,fillcolor=lightgrey];
 *     a [ label = " Trace_pdu"];
 *     b [ label = " dispatcher"];
 *     c [ label = " send_ul_mac_pdu"];
 *     D [ label = " send_Dl_mac_pdu"];
 *     E [ label = " SendFrame"];
 *     F[ label = " _Send_Ra_Mac_Pdu"];
 *      a->b;
 *      b->c;
 *      b->d;
 *  label="Architecture"
 *
 * }
 * \enddot
\section _doxy Doxygen Help
You can use the provided Doxyfile as the configuration file or alternatively run "doxygen -g Doxyfile" to generat the file.
You need at least to set the some variables in the Doxyfile including "PROJECT_NAME","PROJECT_NUMBER","INPUT","IMAGE_PATH".
Doxygen help and commands can be found at http://www.stack.nl/~dimitri/doxygen/commands.html#cmdprotocol

\section _arch Architecture

You need to set the IMAGE_PATH in your Doxyfile

\image html arch.png "Architecture"
\image latex arch.eps "Architecture"

\subsection _mac MAC
thisis the mac
\subsection _rlc RLC
this is the rlc
\subsection _impl Implementation
what about the implementation


*@{*/

#include <pthread.h>
#include <stdint.h>

#include "opt.h"

96 97
int opt_enabled=0;

98 99
//static unsigned char g_PDUBuffer[1600];
//static unsigned int g_PDUOffset;
100

101
char in_ip[40];
laurent's avatar
laurent committed
102
char in_path[FILENAME_MAX];
103
FILE *file_fd = NULL;
laurent's avatar
laurent committed
104 105 106 107 108 109 110 111
pcap_hdr_t file_header = {
  0xa1b2c3d4,   /* magic number */
  2, 4,         /* version number is 2.4 */
  0,            /* timezone */
  0,            /* sigfigs - apparently all tools do this */
  65535,        /* snaplen - this should be long enough */
  MAC_LTE_DLT   /* Data Link Type (DLT).  Set as unused value 147 for now */
};
112 113 114 115 116 117 118 119

trace_mode_t opt_type = OPT_NONE;
static unsigned int subframesSinceCaptureStart;

static int g_socksd = -1;/* UDP socket used for sending frames */
static struct sockaddr_in g_serv_addr;

typedef struct {
120 121 122
  pthread_t thread;
  int sd;
  struct sockaddr_in address;
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
} opt_listener_t;

opt_listener_t opt_listener;

static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
                      guint16 rnti, guint16 ueid, guint16 sysframeNumber,
                      guint8 isPredefinedData, guint8 retx, guint8 crcStatus,
                      guint8 oob_event, guint8 oob_event_value,
                      uint8_t *pdu_buffer, unsigned int pdu_buffer_size);

static int MAC_LTE_PCAP_WritePDU(MAC_Context_Info_t *context,
                                 const unsigned char *PDU, unsigned int length);

static void *opt_listener_thread(void *arg)
{
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
  ssize_t ret;
  struct sockaddr_in from_address;
  socklen_t socklen = sizeof(from_address);

  memset(&from_address, 0, sizeof(from_address));

  while(1) {
    /* Simply drop packets */
    ret = recvfrom(opt_listener.sd, NULL, 0, 0, (struct sockaddr*)&from_address,
                   &socklen);

    if (ret == 0) {
      LOG_D(OPT, "Remote host is no more connected, exiting thread\n");
      pthread_exit(NULL);
    } else if (ret < 0) {
      /* Errors */
      LOG_E(OPT, "An error occured during recvfrom:  %s\n", strerror(errno));
      pthread_exit(NULL);
    } else {
      /* Normal read -> discard PDU */
Cedric Roux's avatar
Cedric Roux committed
158
      LOG_D(OPT, "Incoming data received from: %s:%u with length %zd\n",
159 160
            inet_ntoa(opt_listener.address.sin_addr),
            ntohs(opt_listener.address.sin_port), ret);
161
    }
162
  }
163

164
  return NULL;
165 166 167 168 169
}

static
int opt_create_listener_socket(char *ip_address, uint16_t port)
{
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 195 196
  /* Create an UDP socket and listen on it.
   * Silently discard PDU received.
   */

  int sd = -1;
  int ret = -1;

  memset(&opt_listener, 0, sizeof(opt_listener_t));

  sd = socket(AF_INET, SOCK_DGRAM, 0);

  if (sd < 0) {
    LOG_E(OPT, "Failed to create listener socket: %s\n", strerror(errno));
    sd = -1;
    opt_type = OPT_NONE;
    return -1;
  }

  opt_listener.sd = sd;
  opt_listener.address.sin_family = AF_INET;
  /* Listening only on provided IP address */
  opt_listener.address.sin_addr.s_addr = inet_addr(ip_address);
  opt_listener.address.sin_port = htons(port);

  ret = bind(opt_listener.sd, (struct sockaddr*) &opt_listener.address, sizeof(opt_listener.address));

  if (ret != 0) {
Cedric Roux's avatar
Cedric Roux committed
197 198 199
    LOG_E(OPT, "Failed to bind socket to (%s:%u): %s\n",
          inet_ntoa(opt_listener.address.sin_addr),
          ntohs(opt_listener.address.sin_port), strerror(errno));
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    opt_type = OPT_NONE;
    close(opt_listener.sd);
    opt_listener.sd = -1;
    return -1;
  }

  ret = pthread_create(&opt_listener.thread, NULL, opt_listener_thread, NULL);

  if (ret != 0) {
    LOG_E(OPT, "Failed to create thread for server socket: %s\n", strerror(errno));
    opt_type = OPT_NONE;
    close(opt_listener.sd);
    opt_listener.sd = -1;
    return -1;
  }

  return 0;
217 218 219 220 221 222 223 224 225 226 227 228 229 230
}

//struct mac_lte_info * mac_info;

// #define WIRESHARK_DEV
/* if you want to define this, then you need to
 * 1. checkout the wireshark dev at : svn co http://anonsvn.wireshark.org/wireshark/trunk wireshark
 * 2. copy the local packet-mac-lte.h and packet-mac-lte.c into epan/dissectors/
 * 3. install it, read INSTALL
 * 4. run the wireshark and capture packets from lo interface, and filter out icmp packet (!icmp)
 * 5. run ./oasim -a -P0 -n 30 | grep OPT
 */
/* Add framing header to MAC PDU and send. */
static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType,
231
                      guint16 rnti, guint16 ueid, guint16 sfnSf,
232 233 234 235
                      guint8 isPredefinedData, guint8 retx, guint8 crcStatus,
                      guint8 oob_event, guint8 oob_event_value,
                      uint8_t *pdu_buffer, unsigned int pdu_buffer_size)
{
laurent's avatar
laurent committed
236 237
  unsigned char frameBuffer[9000];
  unsigned int frameOffset;
238

239
  ssize_t bytesSent;
240
  frameOffset = 0;
241 242
  uint16_t tmp16;

243
  memcpy(frameBuffer+frameOffset, MAC_LTE_START_STRING,
244
         strlen(MAC_LTE_START_STRING));
245
  frameOffset += strlen(MAC_LTE_START_STRING);
246 247 248

  /******************************************************************************/
  /* Now write out fixed fields (the mandatory elements of struct mac_lte_info) */
249 250 251
  frameBuffer[frameOffset++] = radioType;
  frameBuffer[frameOffset++] = direction;
  frameBuffer[frameOffset++] = rntiType;
252 253 254 255 256

  /*************************************/
  /* Now optional fields               */

  /* RNTI */
257
  frameBuffer[frameOffset++] = MAC_LTE_RNTI_TAG;
258
  tmp16 = htons(rnti);
259 260
  memcpy(frameBuffer+frameOffset, &tmp16, 2);
  frameOffset += 2;
261 262

  /* UEId */
263
  frameBuffer[frameOffset++] = MAC_LTE_UEID_TAG;
264
  tmp16 = htons(ueid);
265 266
  memcpy(frameBuffer+frameOffset, &tmp16, 2);
  frameOffset += 2;
267 268

  /* Subframe number */
laurent's avatar
laurent committed
269
  frameBuffer[frameOffset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
270
  tmp16 = htons(sfnSf); // frame counter : this will give an expert info as wireshark expects SF and not F
271 272
  memcpy(frameBuffer+frameOffset, &tmp16, 2);
  frameOffset += 2;
273

274 275
  frameBuffer[frameOffset++] = MAC_LTE_CRC_STATUS_TAG;
  frameBuffer[frameOffset++] = crcStatus;
276
  
277
#ifdef WIRESHARK_DEV
278
  frameOffset += 2;
279
  tmp16 = htons(sfnSf); // subframe
280 281
  memcpy(frameBuffer+frameOffset, &tmp16, 2);
  frameOffset += 2;
282 283
#endif

284 285 286
  /***********************************************************/
  /* For these optional fields, no need to encode if value is default */
  if (!isPredefinedData) {
287 288
    frameBuffer[frameOffset++] = MAC_LTE_PREDEFINED_DATA_TAG;
    frameBuffer[frameOffset++] = isPredefinedData;
289 290 291
  }

  if (retx != 0) {
292 293
    frameBuffer[frameOffset++] = MAC_LTE_RETX_TAG;
    frameBuffer[frameOffset++] = retx;
294
  }
295

296
//#ifdef WIRESHARK_DEV
297 298 299 300 301 302

  /* Relating to out-of-band events */
  /* N.B. dissector will only look to these fields if length is 0... */
  if (pdu_buffer_size==0) {
    switch (oob_event) {
    case ltemac_send_preamble :
laurent's avatar
laurent committed
303
      LOG_D(OPT,"ltemac_send_preamble event %02x."
304 305
          //"%02x."
          "%02x.%02x\n",
laurent's avatar
laurent committed
306
          MAC_LTE_SEND_PREAMBLE_TAG,
307 308 309
          //ltemac_send_preamble,
          rnti,
          oob_event_value);
310 311 312
      //frameBuffer[frameOffset++]=0;
      //frameBuffer[frameOffset++]=0;
      //frameBuffer[frameOffset++]=0;
laurent's avatar
laurent committed
313
      frameBuffer[frameOffset++] = MAC_LTE_SEND_PREAMBLE_TAG;
314
      //frameBuffer[frameOffset++]=ltemac_send_preamble;
315 316
      frameBuffer[frameOffset++]=rnti; // is the preamble
      frameBuffer[frameOffset++]=oob_event_value;
317 318 319
      break;

    case ltemac_send_sr:
laurent's avatar
laurent committed
320
      frameBuffer[frameOffset++]=MAC_LTE_SR_TAG ;
321
      frameOffset+=2;
laurent's avatar
laurent committed
322 323
      frameBuffer[frameOffset++]=rnti;
      frameOffset++;
324
      frameBuffer[frameOffset++]=oob_event_value;
laurent's avatar
laurent committed
325
      frameOffset++;
326 327 328 329
      break;

    case ltemac_sr_failure:
    default:
330
      LOG_W(OPT,"not implemeneted yet\n");
331
      break;
332
    }
333 334
  }

335
//#endif
336 337
  /***************************************/
  /* Now write the MAC PDU               */
338
  frameBuffer[frameOffset++] = MAC_LTE_PAYLOAD_TAG;
339
  
340
  /* Append actual PDU  */
341 342
  //memcpy(frameBuffer+frameOffset, g_PDUBuffer, g_PDUOffset);
  //frameOffset += g_PDUOffset;
343
  if (pdu_buffer != NULL) {
344 345
    memcpy(frameBuffer+frameOffset, (void*)pdu_buffer, pdu_buffer_size);
    frameOffset += pdu_buffer_size;
346
  }
347

348
  /* Send out the data over the UDP socket */
349
  bytesSent = sendto(g_socksd, frameBuffer, frameOffset, 0,
350 351
                     (const struct sockaddr *)&g_serv_addr, sizeof(g_serv_addr));

352
  if (bytesSent != frameOffset) {
Cedric Roux's avatar
Cedric Roux committed
353
    LOG_W(OPT, "sendto() failed (not a thread-safe func)- expected %d bytes, got %ld (errno=%d)\n",
354
          frameOffset, bytesSent, errno);
355
    //exit(1);
356
  }
357 358 359 360 361 362
}

/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
static int MAC_LTE_PCAP_WritePDU(MAC_Context_Info_t *context,
                                 const uint8_t *PDU, unsigned int length)
{
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
  pcaprec_hdr_t packet_header;
  uint8_t context_header[256];
  int offset = 0;
  unsigned short tmp16;

  /*****************************************************************/
  /* Context information (same as written by UDP heuristic clients */
  context_header[offset++] = context->radioType;
  context_header[offset++] = context->direction;
  context_header[offset++] = context->rntiType;

  /* RNTI */
  context_header[offset++] = MAC_LTE_RNTI_TAG;
  tmp16 = htons(context->rnti);
  memcpy(context_header+offset, &tmp16, 2);
  offset += 2;

  /* UEId */
  context_header[offset++] = MAC_LTE_UEID_TAG;
  tmp16 = htons(context->ueid);
  memcpy(context_header+offset, &tmp16, 2);
  offset += 2;

  /* Subframe number */
laurent's avatar
laurent committed
387
  context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
  tmp16 = htons(context->subFrameNumber);
  memcpy(context_header+offset, &tmp16, 2);
  offset += 2;

  /* CRC Status */
  context_header[offset++] = MAC_LTE_CRC_STATUS_TAG;
  context_header[offset++] = context->crcStatusOK;

  /* Data tag immediately preceding PDU */
  context_header[offset++] = MAC_LTE_PAYLOAD_TAG;

  /****************************************************************/
  /* PCAP Header                                                  */
  /* TODO: Timestamp might want to be relative to a more sensible
     base time... */
  packet_header.ts_sec = context->subframesSinceCaptureStart / 1000;
  packet_header.ts_usec = (context->subframesSinceCaptureStart % 1000) * 1000;
  packet_header.incl_len = offset + length;
  packet_header.orig_len = offset + length;
407

408 409 410 411 412
  /***************************************************************/
  /* Now write everything to the file                            */
  fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, file_fd);
  fwrite(context_header, 1, offset, file_fd);
  fwrite(PDU, 1, length, file_fd);
413

414
  return 1;
415
}
laurent's avatar
laurent committed
416 417 418
#include <common/ran_context.h>
extern RAN_CONTEXT_t RC;
#include <openair1/PHY/phy_extern_ue.h>
419 420
/* Remote serveraddress (where Wireshark is running) */
void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size,
421
               int ueid, int rntiType, int rnti, uint16_t sysFrameNumber, uint8_t subFrameNumber, int oob_event,
422 423
               int oob_event_value)
{
424
  MAC_Context_Info_t pdu_context;
laurent's avatar
laurent committed
425 426 427 428 429
  int radioType=FDD_RADIO;
  if (RC.eNB[0][0]!=NULL)
    radioType=RC.eNB[0][0]->frame_parms.frame_type== FDD ? FDD_RADIO:TDD_RADIO;
  if (PHY_vars_UE_g[0][0] != NULL)
    radioType=PHY_vars_UE_g[0][0]->frame_parms.frame_type== FDD ? FDD_RADIO:TDD_RADIO;
430 431 432 433
  switch (opt_type) {
  case OPT_WIRESHARK :
    if (g_socksd == -1) {
      return;
434
    }
435

laurent's avatar
laurent committed
436
    SendFrame( radioType,
437
              (direction == DIRECTION_DOWNLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK,
438
              rntiType, rnti, ueid, (sysFrameNumber<<4) + subFrameNumber,
439 440 441 442 443 444 445 446 447 448
              1, 0, 1,  //guint8 isPredefinedData, guint8 retx, guint8 crcStatus
              oob_event,oob_event_value,
              pdu_buffer, pdu_buffer_size);
    break;

  case OPT_PCAP:
    if (file_fd == NULL) {
      return;
    }

laurent's avatar
laurent committed
449
    pdu_context.radioType =  radioType;
450 451 452 453 454 455 456
    pdu_context.direction = (direction == DIRECTION_DOWNLINK) ? DIRECTION_DOWNLINK
                            : DIRECTION_UPLINK;
    pdu_context.rntiType = rntiType;
    pdu_context.rnti = rnti;
    pdu_context.ueid = ueid;
    pdu_context.isRetx = 0;
    pdu_context.crcStatusOK =1;
457 458
    pdu_context.sysFrameNumber = sysFrameNumber;
    pdu_context.subFrameNumber = subFrameNumber;
459 460 461 462 463 464 465 466
    pdu_context.subframesSinceCaptureStart = subframesSinceCaptureStart++;
    MAC_LTE_PCAP_WritePDU( &pdu_context, pdu_buffer, pdu_buffer_size);
    break;

  case OPT_TSHARK:
  default:
    break;
  }
467 468
}
/*---------------------------------------------------*/
laurent's avatar
laurent committed
469
int init_opt(char *path, char *ip)
470
{
471
  uint16_t in_port;
472 473 474 475 476 477
  subframesSinceCaptureStart = 0;

  if (path != NULL) {
    strncpy( in_path, path, sizeof(in_path) );
    in_path[sizeof(in_path) - 1] = 0; // terminate string
  } else {
478
    strcpy( in_path, "/tmp/opt.pcap" );
479 480 481 482 483 484 485 486 487
  }

  if (ip != NULL) {
    strncpy( in_ip, ip, sizeof(in_ip) );
    in_ip[sizeof(in_ip) - 1] = 0; // terminate string
  } else {
    strcpy( in_ip, "127.0.0.1" );
  }

laurent's avatar
laurent committed
488
  in_port = PACKET_MAC_LTE_DEFAULT_UDP_PORT;
489 490 491 492 493 494 495 496

  // trace_mode
  switch (opt_type) {
  case OPT_WIRESHARK:

    /* Create local server socket only if using localhost address */
    if (strcmp(in_ip, "127.0.0.1") == 0) {
      opt_create_listener_socket(in_ip, in_port);
497
    }
498 499 500 501 502 503 504

    g_socksd = socket(AF_INET, SOCK_DGRAM, 0);

    if (g_socksd == -1) {
      LOG_E(OPT, "Error trying to create socket (errno=%d)\n", errno);
      LOG_E(OPT, "CREATING SOCKET FAILED\n");
      return (-1);
505 506
    }

507 508 509 510 511 512 513 514 515 516 517 518
    /* Get remote IP address from the function argument */
    g_serv_addr.sin_family = AF_INET;
    g_serv_addr.sin_port = htons(in_port);
    g_serv_addr.sin_addr.s_addr = inet_addr(in_ip);
    break;

  case OPT_PCAP:
    file_fd = fopen(in_path, "w");

    if (file_fd == NULL) {
      LOG_D(OPT, "Failed to open file \"%s\" for writing\n", in_path);
      return (-1);
519
    }
520 521 522 523 524
    /* Write the file header */
    fwrite(&file_header, sizeof(pcap_hdr_t), 1, file_fd);
    break;

  case OPT_TSHARK:
525
    LOG_W(OPT, "Tshark is currently not supported\n");
526 527 528 529 530
    opt_type = OPT_NONE;
    break;

  default:
    opt_type = OPT_NONE;
531
    LOG_W(OPT, "supported Option\n");
532 533 534 535
    break;
  }

  if ( opt_type == OPT_WIRESHARK )
536
    LOG_E(OPT,"mode Wireshark: ip %s port %d\n", in_ip, in_port);
537
  else if (opt_type == OPT_PCAP)
538
    LOG_E(OPT,"mode PCAB : path is %s \n",in_path);
539
  else
540
    LOG_E(OPT,"Unsupported or unknown mode %d \n", opt_type);
541 542 543 544

  //  mac_info = (mac_info*)malloc16(sizeof(mac_lte_info));
  // memset(mac_info, 0, sizeof(mac_lte_info)+pdu_buffer_size + 8);
  return (1);
545 546 547
}
void terminate_opt(void)
{
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
  /* Close local socket */
  //  free(mac_info);
  if (opt_type != OPT_NONE) {
    pthread_cancel(opt_listener.thread);
  }

  switch (opt_type) {
  case OPT_WIRESHARK:
    close(g_socksd);
    g_socksd = -1;
    break;

  case OPT_PCAP:
    fclose (file_fd);
    file_fd = NULL;
    break;

  default:
    break;
  }
568 569
}