📄 sgsnemu.c
字号:
}
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 + -