aboutsummaryrefslogtreecommitdiffstats
path: root/ggsn/ggsn.c
diff options
context:
space:
mode:
authorjjako <jjako>2003-04-11 09:40:12 +0000
committerjjako <jjako>2003-04-11 09:40:12 +0000
commita7cd249501b869ed518746b301eb92230ec50f50 (patch)
tree685d542efae0d9e14c1bd21ecb64117521f8c5a9 /ggsn/ggsn.c
parentafb2a970de8bcc78142bf0a40a8481012a6d2f34 (diff)
added ippool.h and ippool.c
Diffstat (limited to 'ggsn/ggsn.c')
-rw-r--r--ggsn/ggsn.c311
1 files changed, 151 insertions, 160 deletions
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 3f9767b..322cc9d 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -1,16 +1,16 @@
/*
- * OpenGGSN - Gateway GPRS Support Node
- * Copyright (C) 2002 Mondru AB.
+ * OpenGGSN - Gateway GPRS Support Node
+ * Copyright (C) 2002, 2003 Mondru AB.
*
- * The contents of this file may be used under the terms of the GNU
- * General Public License Version 2, provided that the above copyright
- * notice and this permission notice is included in all copies or
- * substantial portions of the software.
+ * The contents of this file may be used under the terms of the GNU
+ * General Public License Version 2, provided that the above copyright
+ * notice and this permission notice is included in all copies or
+ * substantial portions of the software.
*
- * The initial developer of the original code is
- * Jens Jakobsen <jj@openggsn.org>
+ * The initial developer of the original code is
+ * Jens Jakobsen <jj@openggsn.org>
*
- * Contributor(s):
+ * Contributor(s):
*
*/
@@ -52,17 +52,29 @@
#include <time.h>
#include "tun.h"
+#include "ippool.h"
+#include "syserr.h"
#include "../gtp/pdp.h"
#include "../gtp/gtp.h"
#include "cmdline.h"
-int maxfd = 0; /* For select() */
-int tun_fd = -1; /* Network file descriptor */
+int maxfd = 0; /* For select() */
struct tun_t *tun; /* TUN instance */
+
+struct in_addr listen_;
struct in_addr net, mask; /* Network interface */
-char *ipup, *ipdown; /* Filename of scripts */
-int debug; /* Print debug output */
+struct in_addr dns1, dns2; /* PCO DNS address */
+char *ipup, *ipdown; /* Filename of scripts */
+int debug; /* Print debug output */
+struct ul255_t pco;
+struct ul255_t qos;
+struct ul255_t apn;
+
+struct tun_t *tun; /* TUN instance */
+struct ippool_t *ippool; /* Pool of IP addresses */
+struct gsn_t *gsn; /* GSN instance */
+
/* Used to write process ID to file. Assume someone else will delete */
@@ -94,60 +106,16 @@ int encaps_printf(void *p, void *packet, unsigned len)
return 0;
}
-int getip(struct pdp_t *pdp, void* ipif, struct ul66_t *eua,
- struct in_addr *net, struct in_addr *mask) {
- struct in_addr addr;
- uint32_t ip_start, ip_end, ip_cur;
- struct pdp_t *pdp_;
- struct ul66_t eua_;
-
- if (debug) {
- printf("Begin getip %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
- eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
- }
-
- ip_start = ntoh32(net->s_addr & mask->s_addr);
- ip_end = ntoh32(hton32(ip_start) | ~mask->s_addr);
-
- /* By convention the first address is the network address, and the last */
- /* address is the broadcast address. This way two IP addresses are "lost" */
- ip_start++;
-
- if (eua->l == 0) { /* No address supplied. Find one that is available! */
- /* This routine does linear search. In order to support millions of
- * addresses we should instead keep a linked list of available adresses */
- for (ip_cur = ip_start; ip_cur < ip_end; ip_cur++) {
- addr.s_addr = hton32(ip_cur);
- pdp_ntoeua(&addr, &eua_);
- if (pdp_ipget(&pdp_, ipif, &eua_) == -1) {
- pdp_ntoeua(&addr, &pdp->eua);
- pdp->ipif = ipif;
- return 0;
- };
- }
- return EOF; /* No addresses available */
- }
- else { /* Address supplied */
- if (pdp_ipget(&pdp_, ipif, eua) == -1) {
- pdp->ipif = ipif;
- pdp->eua.l = eua->l;
- memcpy(pdp->eua.v, eua->v, eua->l);
- return 0;
- }
- else return EOF; /* Specified address not available */
- }
-}
-
-
int delete_context(struct pdp_t *pdp) {
if (debug) printf("Deleting PDP context\n");
- pdp_ipdel(pdp);
+ ippool_freeip((struct ippoolm_t *) pdp->peer);
return 0;
}
-
int create_context(struct pdp_t *pdp) {
+ struct in_addr addr;
+ struct ippoolm_t *member;
if (debug) printf("Received create PDP context request\n");
@@ -155,69 +123,43 @@ int create_context(struct pdp_t *pdp) {
/* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */
memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_neg));
+ memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg));
- getip(pdp, tun, &pdp->eua, &net, &mask);
- pdp_ipset(pdp, pdp->ipif, &pdp->eua);
-
- return 0; /* Success */
-}
-
-
-
-int create_tun() {
- char buf[1024];
- char snet[100], smask[100];
-
- if ((tun_fd = tun_newtun((struct tun_t**) &tun)) > maxfd)
- maxfd = tun_fd;
-
- if (tun_fd == -1) {
- printf("Failed to open tun\n");
- exit(1);
+ if (pdp_euaton(&pdp->eua, &addr)) {
+ addr.s_addr = 0; /* Request dynamic */
}
- strncpy(snet, inet_ntoa(net), sizeof(snet));
- snet[sizeof(snet)-1] = 0;
- strncpy(smask, inet_ntoa(mask), sizeof(smask));
- smask[sizeof(smask)-1] = 0;
-
- snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s mtu 1450 netmask %s",
- tun->devname, snet, smask);
- buf[sizeof(buf)-1] = 0;
- if (debug) printf("%s\n", buf);
- system(buf);
-
- if (ipup) {
- /* system("ipup /dev/tun0 192.168.0.10"); */
- snprintf(buf, sizeof(buf), "%s %s %s %s",
- ipup, tun->devname, snet, smask);
- buf[sizeof(buf)-1] = 0;
- if (debug) printf("%s\n", buf);
- system(buf);
+ if (ippool_newip(ippool, &member, &addr)) {
+ return EOF; /* Allready in use, or no more available */
}
- return 0;
+ pdp_ntoeua(&member->addr, &pdp->eua);
+ pdp->peer = &member;
+ pdp->ipif = tun; /* TODO */
+ member->peer = pdp;
+
+ return 0; /* Success */
}
-int encaps_gtp(void *gsn, struct tun_t *tun, void *pack, unsigned len) {
- struct pdp_t *pdp;
- struct in_addr addr;
- struct ul66_t eua;
- /*printf("encaps_gtp. Packet received: forwarding to gtp.\n");*/
- /* First we need to extract the IP destination address */
- memcpy(&addr.s_addr, pack+16, 4); /* This ought to be dest addr */
- pdp_ntoeua(&addr, &eua);
- if (pdp_ipget(&pdp, tun, &eua) == 0) {
- return gtp_gpdu((struct gsn_t*) gsn, pdp, pack, len);
- }
- else {
+/* Callback for receiving messages from tun */
+int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
+ struct ippoolm_t *ipm;
+ struct in_addr dst;
+ struct tun_packet_t *iph = (struct tun_packet_t*) pack;
+
+ dst.s_addr = iph->dst;
+
+ if (ippool_getip(ippool, &ipm, &dst)) {
if (debug) printf("Received packet with no destination!!!\n");
return 0;
}
+
+ if (ipm->peer) /* Check if a peer protocol is defined */
+ gtp_gpdu(gsn, (struct pdp_t*) ipm->peer, pack, len);
+ 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);
@@ -231,16 +173,10 @@ int main(int argc, char **argv)
struct hostent *host;
- struct in_addr listen;
- int gtpfd = -1; /* Network file descriptor */
- struct gsn_t *gsn; /* GSN instance */
-
fd_set fds; /* For select() */
struct timeval idleTime; /* How long to select() */
- struct ul_t qos, apn;
- unsigned char qosh[3], apnh[256];
int timelimit; /* Number of seconds to be connected */
int starttime; /* Time program was started */
@@ -259,7 +195,8 @@ int main(int argc, char **argv)
printf("qos: %#08x\n", args_info.qos_arg);
printf("apn: %s\n", args_info.apn_arg);
printf("net: %s\n", args_info.net_arg);
- printf("mask: %s\n", args_info.mask_arg);
+ printf("dynip: %s\n", args_info.dynip_arg);
+ printf("statip: %s\n", args_info.statip_arg);
printf("ipup: %s\n", args_info.ipup_arg);
printf("ipdown: %s\n", args_info.ipdown_arg);
printf("pidfile: %s\n", args_info.pidfile_arg);
@@ -280,7 +217,8 @@ int main(int argc, char **argv)
printf("qos: %#08x\n", args_info.qos_arg);
printf("apn: %s\n", args_info.apn_arg);
printf("net: %s\n", args_info.net_arg);
- printf("mask: %s\n", args_info.mask_arg);
+ printf("dynip: %s\n", args_info.dynip_arg);
+ printf("statip: %s\n", args_info.statip_arg);
printf("ipup: %s\n", args_info.ipup_arg);
printf("ipdown: %s\n", args_info.ipdown_arg);
printf("pidfile: %s\n", args_info.pidfile_arg);
@@ -326,37 +264,62 @@ int main(int argc, char **argv)
return 1;
}
else {
- memcpy(&listen.s_addr, host->h_addr, host->h_length);
+ memcpy(&listen_.s_addr, host->h_addr, host->h_length);
}
}
else {
- listen.s_addr = htonl(INADDR_ANY);
+ listen_.s_addr = htonl(INADDR_ANY);
}
/* net */
- /* Store net as in_addr */
+ /* Store net as in_addr net and mask */
if (args_info.net_arg) {
- if (!inet_aton(args_info.net_arg, &net)) {
- fprintf(stderr, "%s: Invalid network address: %s!\n",
- PACKAGE, args_info.net_arg);
- syslog(LOG_ERR, "Invalid network address: %s!",
- args_info.net_arg);
- return 1;
+ if(ippool_aton(&net, &mask, args_info.net_arg, 0)) {
+ sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+ "Invalid network address: %s!", args_info.net_arg);
+ return -1;
}
}
- /* mask */
- /* Store mask as in_addr */
- if (args_info.mask_arg) {
- if (!inet_aton(args_info.mask_arg, &mask)) {
- fprintf(stderr, "%s: Invalid network mask: %s!\n",
- PACKAGE, args_info.mask_arg);
- syslog(LOG_ERR, "Invalid network mask: %s!",
- args_info.mask_arg);
- return 1;
+ /* dynip */
+ if (!args_info.dynip_arg) {
+ sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+ "No dynamic address pool given!");
+ return -1;
+ }
+ else {
+ if (ippool_new(&ippool, args_info.dynip_arg,
+ IPPOOL_NONETWORK | IPPOOL_NOBROADCAST)) {
+ sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+ "Failed to allocate IP pool!");
}
}
+ /* DNS1 and DNS2 */
+ dns1.s_addr = 0;
+ if (args_info.pcodns1_arg)
+ inet_aton(args_info.pcodns1_arg, &dns1);
+
+ dns2.s_addr = 0;
+ if (args_info.pcodns2_arg)
+ inet_aton(args_info.pcodns2_arg, &dns2);
+
+ pco.l = 20;
+ pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
+ pco.v[1] = 0x80; /* IPCP */
+ pco.v[2] = 0x21;
+ pco.v[3] = 0x10; /* Length of contents */
+ pco.v[4] = 0x02; /* ACK */
+ pco.v[5] = 0x00; /* ID: Need to match request */
+ pco.v[6] = 0x00; /* Length */
+ pco.v[7] = 0x10;
+ pco.v[8] = 0x81; /* DNS 1 */
+ pco.v[9] = 0x06;
+ memcpy(&pco.v[10], &dns1, sizeof(dns1));
+ pco.v[14] = 0x83;
+ pco.v[15] = 0x06; /* DNS 2 */
+ memcpy(&pco.v[16], &dns2, sizeof(dns2));
+
/* ipup */
ipup = args_info.ipup_arg;
@@ -369,35 +332,64 @@ int main(int argc, char **argv)
/* qos */
qos.l = 3;
- qos.v = qosh;
qos.v[2] = (args_info.qos_arg) & 0xff;
qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
-
+
/* apn */
- if (strlen(args_info.apn_arg)>(sizeof(apnh)-1)) {
- printf("invalid APN\n");
- exit(1);
+ if (strlen(args_info.apn_arg) > (sizeof(apn.v)-1)) {
+ printf("Invalid APN\n");
+ return -1;
}
apn.l = strlen(args_info.apn_arg) + 1;
- apn.v = apnh;
apn.v[0] = (char) strlen(args_info.apn_arg);
- strncpy(&apn.v[1], args_info.apn_arg, (sizeof(apnh)-1));
+ strncpy(&apn.v[1], args_info.apn_arg, sizeof(apn.v)-1);
+
+
if (debug) printf("gtpclient: Initialising GTP tunnel\n");
- if ((gtpfd = gtp_new(&gsn, args_info.statedir_arg, &listen)) > maxfd)
- maxfd = gtpfd;
-
- if ((gtpfd = gtp_fd(gsn)) > maxfd)
- maxfd = gtpfd;
+ if (gtp_new(&gsn, args_info.statedir_arg, &listen_)) {
+ sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+ "Failed to create gtp");
+ exit(1);
+ }
+ if (gsn->fd > maxfd) maxfd = gsn->fd;
gtp_set_cb_gpdu(gsn, encaps_tun);
gtp_set_cb_delete_context(gsn, delete_context);
-
gtp_set_cb_create_context(gsn, create_context);
- create_tun();
+
+
+ /* 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_setaddr(tun, &net, &net, &mask);
+ tun_set_cb_ind(tun, cb_tun_ind);
+ if (tun->fd > maxfd) maxfd = tun->fd;
+
+ if (ipup) {
+ char buf[1024];
+ char snet[100];
+ char smask[100];
+
+ strncpy(snet, inet_ntoa(net), sizeof(snet));
+ snet[sizeof(snet)-1] = 0;
+ strncpy(smask, inet_ntoa(mask), sizeof(smask));
+ smask[sizeof(smask)-1] = 0;
+
+ /* system("ipup /dev/tun0 192.168.0.10"); */
+ snprintf(buf, sizeof(buf), "%s %s %s %s",
+ ipup, tun->devname, snet, smask);
+ buf[sizeof(buf)-1] = 0;
+ if (debug) printf("%s\n", buf);
+ system(buf);
+ }
/******************************************************************/
/* Main select loop */
@@ -406,8 +398,8 @@ int main(int argc, char **argv)
while (((starttime + timelimit) > time(NULL)) || (0 == timelimit)) {
FD_ZERO(&fds);
- if (tun_fd != -1) FD_SET(tun_fd, &fds);
- if (gtpfd != -1) FD_SET(gtpfd, &fds);
+ if (tun) FD_SET(tun->fd, &fds);
+ FD_SET(gsn->fd, &fds);
gtp_retranstimeout(gsn, &idleTime);
switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
@@ -418,26 +410,25 @@ int main(int argc, char **argv)
syslog(LOG_ERR, "GGSN: select = -1");
break;
case 0:
+ /* printf("Select returned 0\n"); */
gtp_retrans(gsn); /* Only retransmit if nothing else */
break;
default:
break;
}
- if (tun_fd != -1 && FD_ISSET(tun_fd, &fds) &&
- tun_decaps(tun, encaps_gtp, gsn) < 0) {
- syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun_fd);
+ if (tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
+ tun_decaps(tun) < 0) {
+ syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun->fd);
}
- if (gtpfd != -1 && FD_ISSET(gtpfd, &fds) &&
- gtp_decaps(gsn) < 0) {
- syslog(LOG_ERR, "GTP read failed (gtpfd)=(%d)", gtpfd);
- }
-
+ if (FD_ISSET(gsn->fd, &fds))
+ gtp_decaps(gsn);
}
gtp_free(gsn);
+ tun_free(tun);
return 1;