diff options
author | jjako <jjako> | 2004-02-05 20:39:57 +0000 |
---|---|---|
committer | jjako <jjako> | 2004-02-05 20:39:57 +0000 |
commit | 1f1586458fc940f487058b1bc0169eea1735eeb4 (patch) | |
tree | 51785635ece734b4b04f163d9f7d143b9bb2ed58 | |
parent | 409b855839ea5035af48690c62f6340830267e13 (diff) |
Added IP address alias capability for FreeBSD
-rw-r--r-- | ggsn/ggsn.c | 2 | ||||
-rw-r--r-- | ggsn/tun.c | 45 | ||||
-rw-r--r-- | gtp/gtp.c | 16 | ||||
-rw-r--r-- | sgsnemu/tun.c | 45 |
4 files changed, 84 insertions, 24 deletions
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index b75b01d..c0592c9 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -90,7 +90,7 @@ void log_pid(char *pidfile) { fclose(file); } -#ifdef __sun__ +#if defined(_sun__) int daemon(int nochdir, int noclose) { int fd; @@ -343,22 +343,28 @@ int tun_addaddr(struct tun_t *this, /* TODO: Is this needed on FreeBSD? */ if (!this->addrs) /* Use ioctl for first addr to make ping work */ - return tun_setaddr(this, addr, dstaddr, netmask); + return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */ memset(&areq, 0, sizeof(areq)); /* Set up interface name */ strncpy(areq.ifra_name, this->devname, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ + areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ - ((struct sockaddr_in) areq.ifra_addr).sin_family = AF_INET; - ((struct sockaddr_in) areq.ifra_addr).sin_len = sizeof(areq.ifra_addr); - ((struct sockaddr_in) areq.ifra_addr).sin_addr.s_addr = addr->s_addr; + ((struct sockaddr_in*) &areq.ifra_addr)->sin_family = AF_INET; + ((struct sockaddr_in*) &areq.ifra_addr)->sin_len = sizeof(areq.ifra_addr); + ((struct sockaddr_in*) &areq.ifra_addr)->sin_addr.s_addr = addr->s_addr; - ((struct sockaddr_in) areq.ifra_mask).sin_family = AF_INET; - ((struct sockaddr_in) areq.ifra_mask).sin_len = sizeof(areq.ifra_mask); - ((struct sockaddr_in) areq.ifra_mask).sin_addr.s_addr = netmask->s_addr; + ((struct sockaddr_in*) &areq.ifra_mask)->sin_family = AF_INET; + ((struct sockaddr_in*) &areq.ifra_mask)->sin_len = sizeof(areq.ifra_mask); + ((struct sockaddr_in*) &areq.ifra_mask)->sin_addr.s_addr = netmask->s_addr; + /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */ + ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_family = AF_INET; + ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_len = + sizeof(areq.ifra_broadaddr); + ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_addr.s_addr = + dstaddr->s_addr; /* Create a channel to the NET kernel. */ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { @@ -607,6 +613,8 @@ int tun_new(struct tun_t **tun) #elif defined(__FreeBSD__) char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */ int devnum; + struct ifaliasreq areq; + int fd; #elif defined(__sun__) int if_fd, ppa = -1; @@ -663,6 +671,27 @@ int tun_new(struct tun_t **tun) snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum); (*tun)->devname[sizeof((*tun)->devname)] = 0; + + /* The tun device we found might have "old" IP addresses allocated */ + /* We need to delete those. This problem is not present on Linux */ + + memset(&areq, 0, sizeof(areq)); + + /* Set up interface name */ + strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ); + areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ + + /* Create a channel to the NET kernel. */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "socket() failed"); + return -1; + } + + /* Delete any IP addresses until SIOCDIFADDR fails */ + while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1); + + close(fd); return 0; #elif defined(__sun__) @@ -407,7 +407,7 @@ int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp, memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = *inetaddr; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) addr.sin_len = sizeof(addr); #endif @@ -766,7 +766,7 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, addr.sin_family = AF_INET; addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ addr.sin_port = htons(GTP0_PORT); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) addr.sin_len = sizeof(addr); #endif @@ -787,7 +787,7 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, addr.sin_family = AF_INET; addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ addr.sin_port = htons(GTP1C_PORT); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) addr.sin_len = sizeof(addr); #endif @@ -808,7 +808,7 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, addr.sin_family = AF_INET; addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ addr.sin_port = htons(GTP1U_PORT); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) addr.sin_len = sizeof(addr); #endif @@ -2944,7 +2944,7 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp, memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) addr.sin_len = sizeof(addr); #endif @@ -2965,7 +2965,8 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp, if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) { gsn->err_memcpy++; gtp_err(LOG_ERR, __FILE__, __LINE__, - "Memcpy failed"); + "Memcpy failed: %d > %d", len, + sizeof (union gtp_packet) - sizeof(struct gtp0_header)); return EOF; } memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */ @@ -2985,7 +2986,8 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp, if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) { gsn->err_memcpy++; gtp_err(LOG_ERR, __FILE__, __LINE__, - "Memcpy failed"); + "Memcpy failed: %d > %d", len, + sizeof (union gtp_packet) - sizeof(struct gtp0_header)); return EOF; } memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */ diff --git a/sgsnemu/tun.c b/sgsnemu/tun.c index 208cca6..b406fdb 100644 --- a/sgsnemu/tun.c +++ b/sgsnemu/tun.c @@ -343,22 +343,28 @@ int tun_addaddr(struct tun_t *this, /* TODO: Is this needed on FreeBSD? */ if (!this->addrs) /* Use ioctl for first addr to make ping work */ - return tun_setaddr(this, addr, dstaddr, netmask); + return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */ memset(&areq, 0, sizeof(areq)); /* Set up interface name */ strncpy(areq.ifra_name, this->devname, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ + areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ - ((struct sockaddr_in) areq.ifra_addr).sin_family = AF_INET; - ((struct sockaddr_in) areq.ifra_addr).sin_len = sizeof(areq.ifra_addr); - ((struct sockaddr_in) areq.ifra_addr).sin_addr.s_addr = addr->s_addr; + ((struct sockaddr_in*) &areq.ifra_addr)->sin_family = AF_INET; + ((struct sockaddr_in*) &areq.ifra_addr)->sin_len = sizeof(areq.ifra_addr); + ((struct sockaddr_in*) &areq.ifra_addr)->sin_addr.s_addr = addr->s_addr; - ((struct sockaddr_in) areq.ifra_mask).sin_family = AF_INET; - ((struct sockaddr_in) areq.ifra_mask).sin_len = sizeof(areq.ifra_mask); - ((struct sockaddr_in) areq.ifra_mask).sin_addr.s_addr = netmask->s_addr; + ((struct sockaddr_in*) &areq.ifra_mask)->sin_family = AF_INET; + ((struct sockaddr_in*) &areq.ifra_mask)->sin_len = sizeof(areq.ifra_mask); + ((struct sockaddr_in*) &areq.ifra_mask)->sin_addr.s_addr = netmask->s_addr; + /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */ + ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_family = AF_INET; + ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_len = + sizeof(areq.ifra_broadaddr); + ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_addr.s_addr = + dstaddr->s_addr; /* Create a channel to the NET kernel. */ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { @@ -607,6 +613,8 @@ int tun_new(struct tun_t **tun) #elif defined(__FreeBSD__) char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */ int devnum; + struct ifaliasreq areq; + int fd; #elif defined(__sun__) int if_fd, ppa = -1; @@ -663,6 +671,27 @@ int tun_new(struct tun_t **tun) snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum); (*tun)->devname[sizeof((*tun)->devname)] = 0; + + /* The tun device we found might have "old" IP addresses allocated */ + /* We need to delete those. This problem is not present on Linux */ + + memset(&areq, 0, sizeof(areq)); + + /* Set up interface name */ + strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ); + areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */ + + /* Create a channel to the NET kernel. */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, errno, + "socket() failed"); + return -1; + } + + /* Delete any IP addresses until SIOCDIFADDR fails */ + while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1); + + close(fd); return 0; #elif defined(__sun__) |