⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sgsnemu.c

📁 NGN-3G核心部件SGSN的代码实现
💻 C
📖 第 1 页 / 共 3 页
字号:
  }
  if (count>0)
    sum += * (unsigned char *) p;
  while (sum>>16) 
    sum = (sum & 0xffff) + (sum >> 16);
  pack.checksum = ~sum;

  ntransmitted++;
  return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
}
		

int delete_context(struct pdp_t *pdp) {

  if (tun && options.ipdown) tun_runscript(tun, options.ipdown);

  ipdel((struct iphash_t*) pdp->peer);
  memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */

  if (1 == options.contexts)
    state = 5;  /* Disconnected */

  return 0;
}


/* Callback for receiving messages from tun */
int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
  struct iphash_t *ipm;
  struct in_addr src;
  struct tun_packet_t *iph = (struct tun_packet_t*) pack;

  src.s_addr = iph->src;

  if (ipget(&ipm, &src)) {
    printf("Received packet without a valid source address!!!\n");
    return 0;
  }
  
  if (ipm->pdp) /* Check if a peer protocol is defined */
    gtp_data_req(gsn, ipm->pdp, pack, len);
  return 0;
}

int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
  struct in_addr addr;

  struct iphash_t *iph = (struct iphash_t*) cbp;

  if (cause < 0) {
    printf("Create PDP Context Request timed out\n");
    if (iph->pdp->version == 1) {
      printf("Retrying with version 0\n");
      iph->pdp->version = 0;
      gtp_create_context_req(gsn, iph->pdp, iph);
      return 0;
    }
    else {
      state = 0;
      pdp_freepdp(iph->pdp);
      iph->pdp = NULL;
      return EOF;
    }
  }

  if (cause != 128) {
    printf("Received create PDP context response. Cause value: %d\n", cause);
    state = 0;
    pdp_freepdp(iph->pdp);
    iph->pdp = NULL;
    return EOF; /* Not what we expected */
  }

  if (pdp_euaton(&pdp->eua, &addr)) {
    printf("Received create PDP context response. Cause value: %d\n", cause);
    pdp_freepdp(iph->pdp);
    iph->pdp = NULL;
    state = 0;
    return EOF; /* Not a valid IP address */
  }

  printf("Received create PDP context response. IP address: %s\n", 
	 inet_ntoa(addr));

  if ((options.createif) && (!options.net.s_addr)) {
    struct in_addr m;
#ifdef HAVE_INET_ATON
    inet_aton("255.255.255.255", &m);
#else
    m.s_addr = -1;
#endif
    /* printf("Setting up interface and routing\n");*/
    tun_addaddr(tun, &addr,  &addr, &m);
    if (options.defaultroute) {
      struct in_addr rm;
      rm.s_addr = 0;
      tun_addroute(tun, &rm,  &addr, &rm);
    }
    if (options.ipup) tun_runscript(tun, options.ipup);
  }
    
  ipset((struct iphash_t*) pdp->peer, &addr);
  
  state = 2;                      /* Connected */

  return 0;
}

int delete_pdp_conf(struct pdp_t *pdp, int cause) {
  printf("Received delete PDP context response. Cause value: %d\n", cause);
  return 0;
}

int echo_conf(int recovery) {

  if (recovery < 0) {
    printf("Echo Request timed out\n");
    if (echoversion == 1) {
      printf("Retrying with version 0\n");
      echoversion = 0;
      gtp_echo_req(gsn, echoversion, NULL, &options.remote);
      return 0;
    }
    else {
      state = 0;
      return EOF;
    }
  }
  else {
    printf("Received echo response\n");
    if (!options.contexts) state = 5;
  }
  return 0;
}

int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
  /* if (cause < 0) return 0; Some error occurred. We don't care */
  switch (type) {
  case GTP_ECHO_REQ:
    return echo_conf(cause);
  case GTP_CREATE_PDP_REQ:
    return create_pdp_conf(pdp, cbp, cause);
  case GTP_DELETE_PDP_REQ:
    if (cause !=128) return 0; /* Request not accepted. We don't care */
    return delete_pdp_conf(pdp, cause);
  default:
    return 0;
  }
}


int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
  /*  printf("encaps_tun. Packet received: forwarding to tun\n");*/
  return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
}

int main(int argc, char **argv)
{
  fd_set fds;			/* For select() */
  struct timeval idleTime;	/* How long to select() */
  struct pdp_t *pdp;
  int n;
  int starttime = time(NULL);   /* Time program was started */
  int stoptime = 0;             /* Time to exit */
  int pingtimeout = 0;          /* Time to print ping statistics */

  struct timezone tz;           /* Used for calculating ping times */
  struct timeval tv;
  int diff;

  /* open a connection to the syslog daemon */
  /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
  /* TODO: Only use LOG__PERROR for linux */

#ifdef __linux__
  openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
#else
  openlog(PACKAGE, (LOG_PID), LOG_DAEMON);
#endif


  /* Process options given in configuration file and command line */
  if (process_options(argc, argv)) 
    exit(1);

  printf("\nInitialising GTP library\n");
  if (gtp_new(&gsn, options.statedir,  &options.listen, GTP_MODE_SGSN)) {
    sys_err(LOG_ERR, __FILE__, __LINE__, 0,
	    "Failed to create gtp");
    exit(1);
  }
  if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
  if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
  if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;

  gtp_set_cb_delete_context(gsn, delete_context);
  gtp_set_cb_conf(gsn, conf);
  if (options.createif) 
    gtp_set_cb_data_ind(gsn, encaps_tun);
  else
    gtp_set_cb_data_ind(gsn, encaps_ping);

  if (options.createif) {
    printf("Setting up interface\n");
    /* Create a tunnel interface */
    if (tun_new((struct tun_t**) &tun)) {
      sys_err(LOG_ERR, __FILE__, __LINE__, 0,
	      "Failed to create tun");
      exit(1);
    }
    tun_set_cb_ind(tun, cb_tun_ind);
    if (tun->fd > maxfd) maxfd = tun->fd;
  }

  if ((options.createif) && (options.net.s_addr)) {
    /* printf("Setting up interface and routing\n");*/
    tun_addaddr(tun, &options.netaddr,  &options.destaddr, &options.mask);
    if (options.defaultroute) {
      struct in_addr rm;
      rm.s_addr = 0;
      tun_addroute(tun, &rm, &options.destaddr, &rm);
    }
    if (options.ipup) tun_runscript(tun, options.ipup);
  }


  /* Initialise hash tables */
  memset(&iphash, 0, sizeof(iphash));  
  memset(&iparr, 0, sizeof(iparr));  

  printf("Done initialising GTP library\n\n");

  /* See if anybody is there */
  printf("Sending off echo request\n");
  echoversion = options.gtpversion;
  gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */

  for(n=0; n<options.contexts; n++) {
    uint64_t myimsi;
    printf("Setting up PDP context #%d\n", n);
    iparr[n].inuse = 1; /* TODO */

    imsi_add(options.imsi, &myimsi, n);

    /* Allocated here. */
    /* If create context failes we have to deallocate ourselves. */
    /* Otherwise it is deallocated by gtplib */
    pdp_newpdp(&pdp, myimsi, options.nsapi, NULL); 

    pdp->peer = &iparr[n];
    pdp->ipif = tun; /* TODO */
    iparr[n].pdp = pdp;

    if (options.qos.l > sizeof(pdp->qos_req0)) {
      sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
      exit(1);
    }
    else {
      memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
    }

    /* TODO */
    pdp->qos_req.l = 4;
    pdp->qos_req.v[0] = 0x00;
    memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
    
    pdp->selmode = options.selmode;
    
    if (options.apn.l > sizeof(pdp->apn_use.v)) {
      sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
      exit(1);
    }
    else {
      pdp->apn_use.l = options.apn.l;
      memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
    }
    
    pdp->gsnlc.l = sizeof(options.listen);
    memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
    pdp->gsnlu.l = sizeof(options.listen);
    memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
    
    if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
      sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
      exit(1);
    }
    else {
      msisdn_add(&options.msisdn, &pdp->msisdn, n);
    }
    
    ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
    
    if (options.pco.l > sizeof(pdp->pco_req.v)) {
      sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
      exit(1);
    }
    else {
      pdp->pco_req.l = options.pco.l;
      memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
    }
    
    pdp->version = options.gtpversion;

    pdp->hisaddr0 = options.remote;
    pdp->hisaddr1 = options.remote;

    pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid, 
				   512 = Flat rate, 256 = Hot billing */

    /* Create context */
    /* We send this of once. Retransmissions are handled by gtplib */
    gtp_create_context_req(gsn, pdp, &iparr[n]);
  }    

  state = 1;  /* Enter wait_connection state */

  printf("Waiting for response from ggsn........\n\n");


  /******************************************************************/
  /* Main select loop                                               */
  /******************************************************************/

  while ((0 != state) && (5 != state)) {

    /* Take down client after timeout after disconnect */
    if ((4 == state) && ((stoptime) <= time(NULL))) {
      state = 5;
    }

    /* Take down client after timelimit timeout */
    if ((2 == state) && (options.timelimit) && 
	((starttime + options.timelimit) <= time(NULL))) {
      state = 3;
    }

    /* Take down client after ping timeout */
    if ((2 == state) &&  (pingtimeout) && (pingtimeout <= time(NULL))) {
      state = 3;
    }

    /* Set pingtimeout for later disconnection */
    if (options.pingcount && ntransmitted >= options.pingcount) {
      pingtimeout = time(NULL) + 5; /* Extra seconds */
    }

    /* Print statistics if no more ping packets are missing */
    if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
      ping_finish();
      if (!options.createif)
	state = 3;
    }    

    /* Send off disconnect */
    if (3 == state) {
      state = 4;
      stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
      for(n=0; n<options.contexts; n++) {
	/* Delete context */
	printf("Disconnecting PDP context #%d\n", n);
	gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
	if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
      }
    }

    /* Send of ping packets */
    diff = 0;
    while (( diff<=0 ) && 
	   /* Send off an ICMP ping packet */
	   /*if (*/(options.pinghost.s_addr) && (2 == state) && 
	   ((pingseq < options.pingcount) || (options.pingcount == 0))) {
      if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
      gettimeofday(&tv, &tz);
      diff = 1000000 / options.pingrate * pingseq -
	1000000 * (tv.tv_sec - firstping.tv_sec) -
	(tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
      if (diff <=0) {
	if (options.debug) printf("Create_ping %d\n", diff);
	create_ping(gsn, iparr[pingseq % options.contexts].pdp,
		    &options.pinghost, pingseq, options.pingsize);
	pingseq++;
      }
    }

    FD_ZERO(&fds);
    if (tun) FD_SET(tun->fd, &fds);
    FD_SET(gsn->fd0, &fds);
    FD_SET(gsn->fd1c, &fds);
    FD_SET(gsn->fd1u, &fds);
    
    gtp_retranstimeout(gsn, &idleTime);
    ping_timeout(&idleTime);
    
    if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
			      (int) idleTime.tv_sec, (int) idleTime.tv_usec);
    
    switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
    case -1:
      sys_err(LOG_ERR, __FILE__, __LINE__, 0,
	      "Select returned -1");
      break;  
    case 0:
      gtp_retrans(gsn); /* Only retransmit if nothing else */
      break; 
    default:
      break;
    }
    
    if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
      sys_err(LOG_ERR, __FILE__, __LINE__, 0,
	      "TUN decaps failed");
    }
    
    if (FD_ISSET(gsn->fd0, &fds))
      gtp_decaps0(gsn);

    if (FD_ISSET(gsn->fd1c, &fds))
      gtp_decaps1c(gsn);

    if (FD_ISSET(gsn->fd1u, &fds))
      gtp_decaps1u(gsn);
  }
  
  gtp_free(gsn); /* Clean up the gsn instance */
  
  if (options.createif)
    tun_free(tun);

  if (0 == state)
    exit(1); /* Indicate error */
  
  return 0; 
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -