diff options
author | jjako <jjako> | 2003-07-06 20:53:57 +0000 |
---|---|---|
committer | jjako <jjako> | 2003-07-06 20:53:57 +0000 |
commit | 1db1c81302902cdaa34fbc9953abd08cfb70f0f0 (patch) | |
tree | ed49bf4faffd7ede3ff5ba27f2e7aed0da6a2d18 | |
parent | 88c2216e8eec9be3a3aa08f1020d045a31d291e1 (diff) |
Improved GTP error handling
-rw-r--r-- | ggsn/ggsn.c | 2 | ||||
-rw-r--r-- | gtp/gtp.c | 184 | ||||
-rw-r--r-- | gtp/gtp.h | 17 |
3 files changed, 157 insertions, 46 deletions
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index ea5a196..163e602 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -363,7 +363,7 @@ int main(int argc, char **argv) if (debug) printf("gtpclient: Initialising GTP tunnel\n"); - if (gtp_new(&gsn, args_info.statedir_arg, &listen_)) { + if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) { sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Failed to create gtp"); exit(1); @@ -54,6 +54,55 @@ #include "gtpie.h" #include "queue.h" + +/* Error reporting functions */ + +void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) { + va_list args; + char buf[ERRMSG_SIZE]; + + va_start(args, fmt); + vsnprintf(buf, ERRMSG_SIZE, fmt, args); + va_end(args); + buf[ERRMSG_SIZE-1] = 0; + syslog(priority, "%s: %d: %s", filename, linenum, buf); +} + +void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer, + void *pack, unsigned len, char *fmt, ...) { + + va_list args; + char buf[ERRMSG_SIZE]; + char buf2[ERRMSG_SIZE]; + int n; + int pos; + + va_start(args, fmt); + vsnprintf(buf, ERRMSG_SIZE, fmt, args); + va_end(args); + buf[ERRMSG_SIZE-1] = 0; + + snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:", + inet_ntoa(peer->sin_addr), + ntohs(peer->sin_port), + len); + buf2[ERRMSG_SIZE-1] = 0; + pos = strlen(buf2); + for(n=0; n<len; n++) { + if ((pos+4)<ERRMSG_SIZE) { + sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]); + pos += 3; + } + } + buf2[pos] = 0; + + syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2); + +} + + + + /* API Functions */ const char* gtp_version() @@ -80,6 +129,65 @@ int gtp_create_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid, return gtp_create_pdp_req(gsn, version, aid, inetaddr, pdp); } +int gtp_create_context2(struct gsn_t *gsn, void *aid, + struct in_addr* inetaddr, + int selmode, uint64_t imsi, int nsapi, + uint8_t *qos, int qoslen, + char *apn, int apnlen, + char *msisdn, int msisdnlen, + uint8_t *pco, int pcolen) { + int version = 0; + + struct pdp_t *pdp; + + if (qoslen > sizeof(pdp->qos_req0)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big"); + return -1; + } + + if (apnlen > sizeof(pdp->apn_use.v)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big"); + return -1; + } + + if (msisdnlen > sizeof(pdp->msisdn.v)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big"); + return -1; + } + + if (pcolen > sizeof(pdp->pco_req.v)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big"); + return -1; + } + + /* New pdp allocated here:*/ + pdp_newpdp(&pdp, imsi, nsapi, NULL); + + pdp->peer = aid; + pdp->ipif = NULL; + + pdp->selmode = selmode; + + memcpy(pdp->qos_req0, qos, qoslen); /* Length checked above */ + pdp->apn_use.l = apnlen; + memcpy(pdp->apn_use.v, apn, apnlen); /* Length checked above */ + + pdp->gsnlc.l = sizeof(gsn->gsnc); + memcpy(pdp->gsnlc.v, &gsn->gsnc, sizeof(gsn->gsnc)); + pdp->gsnlu.l = sizeof(gsn->gsnc); + memcpy(pdp->gsnlu.v, &gsn->gsnc, sizeof(gsn->gsnc)); + + pdp->msisdn.l = msisdnlen; + memcpy(pdp->msisdn.v, msisdn, msisdnlen); + + ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */ + + pdp->pco_req.l = pcolen; + memcpy(pdp->pco_req.v, pco, pcolen); + + return gtp_create_pdp_req(gsn, version, aid, inetaddr, pdp); +} + int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid, struct in_addr* inetaddr) { int version = 0; @@ -213,49 +321,6 @@ char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer, return buf; } -void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) { - va_list args; - char buf[ERRMSG_SIZE]; - - va_start(args, fmt); - vsnprintf(buf, ERRMSG_SIZE, fmt, args); - va_end(args); - buf[ERRMSG_SIZE-1] = 0; - syslog(priority, "%s: %d: %s", filename, linenum, buf); -} - -void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer, - void *pack, unsigned len, char *fmt, ...) { - - va_list args; - char buf[ERRMSG_SIZE]; - char buf2[ERRMSG_SIZE]; - int n; - int pos; - - va_start(args, fmt); - vsnprintf(buf, ERRMSG_SIZE, fmt, args); - va_end(args); - buf[ERRMSG_SIZE-1] = 0; - - snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:", - inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port), - len); - buf2[ERRMSG_SIZE-1] = 0; - pos = strlen(buf2); - for(n=0; n<len; n++) { - if ((pos+4)<ERRMSG_SIZE) { - sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]); - pos += 3; - } - } - buf2[pos] = 0; - - syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2); - -} - /* *********************************************************** * Reliable delivery of signalling messages @@ -560,7 +625,8 @@ static void log_restart(struct gsn_t *gsn) { -int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen) +int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, + int mode) { struct sockaddr_in addr; int gtp_fd; @@ -1720,6 +1786,14 @@ int gtp_gpdu_ind(struct gsn_t *gsn, int version, return gtp_error_ind_resp(gsn, version, peer, pack, len); } + + /* If the GPDU was not from the peer GSN tell him to delete context */ + if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */ + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_error_ind_resp(gsn, version, peer, pack, len); + } /* Callback function */ if (gsn->cb_gpdu !=0) @@ -1801,6 +1875,28 @@ int gtp_decaps(struct gsn_t *gsn) "GTP0 packet too short"); continue; /* Silently discard 29.60: 11.1.2 */ } + + if ((gsn->mode == GTP_MODE_GGSN) && + ((pheader->type == GTP_CREATE_PDP_RSP) || + (pheader->type == GTP_UPDATE_PDP_RSP) || + (pheader->type == GTP_DELETE_PDP_RSP))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + + if ((gsn->mode == GTP_MODE_SGSN) && + ((pheader->type == GTP_CREATE_PDP_REQ) || + (pheader->type == GTP_UPDATE_PDP_REQ) || + (pheader->type == GTP_DELETE_PDP_REQ))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + + switch (pheader->type) { case GTP_ECHO_REQ: @@ -19,6 +19,9 @@ #define GTP_DEBUG 0 /* Print debug information */ +#define GTP_MODE_GGSN 1 +#define GTP_MODE_SGSN 2 + #define GTP0_PORT 3386 #define GTP1C_PORT 2123 #define GTP1U_PORT 2152 @@ -186,6 +189,7 @@ struct gsn_t { /* Parameters related to the network interface */ int fd; /* File descriptor to network interface */ + int mode; /* Mode of operation: GGSN or SGSN */ struct in_addr gsnc; /* IP address of this gsn for signalling */ struct in_addr gsnu; /* IP address of this gsn for user traffic */ @@ -234,7 +238,9 @@ struct gsn_t { /* External API functions */ extern const char* gtp_version(); -extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen); +extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, + int mode); + extern int gtp_free(struct gsn_t *gsn); extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, @@ -247,6 +253,15 @@ extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid, struct in_addr* inetaddr); extern int gtp_delete_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid); +extern int +gtp_create_context2(struct gsn_t *gsn, void *aid, + struct in_addr* inetaddr, + int selmode, uint64_t imsi, int nsapi, + uint8_t *qos, int qoslen, + char *apn, int apnlen, + char *msisdn, int msisdnlen, + uint8_t *pco, int pcolen); + extern int gtp_gpdu(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len); |