129 lines
3.2 KiB
C
129 lines
3.2 KiB
C
/*
|
|
* OpenGGSN - Gateway GPRS Support Node
|
|
* Copyright (C) 2002 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 initial developer of the original code is
|
|
* Jens Jakobsen <jj@openggsn.org>
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* tun.c: Contains all TUN functionality. Should be able to handle multiple
|
|
* tunnels in the same program. Each tunnel is identified by the socket.
|
|
* I suppose that no other state information than the socket is needed.
|
|
*
|
|
* - tun_newtun: Initialise TUN tunnel.
|
|
* - tun_freetun: Free a device previously created with tun_newtun.
|
|
* - tun_encaps: Encapsulate packet in TUN tunnel and send off
|
|
* - tun_decaps: Extract packet from TUN tunnel and call function to
|
|
* ship it off as GTP encapsulated packet.
|
|
*
|
|
* TODO:
|
|
* - Do we need to handle fragmentation?
|
|
*/
|
|
|
|
|
|
#include <syslog.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <linux/if.h>
|
|
#include <errno.h>
|
|
#include <linux/if_tun.h>
|
|
|
|
|
|
#include "tun.h"
|
|
|
|
|
|
int tun_newtun(struct tun_t **tun)
|
|
{
|
|
struct ifreq ifr;
|
|
|
|
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
|
|
syslog(LOG_ERR, "%s %d. calloc(nmemb=%d, size=%d) failed: Error = %s(%d)",
|
|
__FILE__, __LINE__, 1, sizeof(struct tun_t),
|
|
strerror(errno), errno);
|
|
return EOF;
|
|
}
|
|
|
|
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
|
syslog(LOG_ERR, "TUN: open() failed");
|
|
return -1;
|
|
}
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
|
|
strncpy(ifr.ifr_name, (*tun)->devname, IFNAMSIZ);
|
|
|
|
if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
|
|
syslog(LOG_ERR, "TUN: ioctl() failed");
|
|
close((*tun)->fd);
|
|
return -1;
|
|
}
|
|
|
|
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
|
|
|
|
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
|
|
|
|
return (*tun)->fd;
|
|
}
|
|
|
|
int tun_freetun(struct tun_t *tun)
|
|
{
|
|
if (close(tun->fd)) {
|
|
syslog(LOG_ERR, "%s %d. close(fd=%d) failed: Error = %s",
|
|
__FILE__, __LINE__, tun->fd, strerror(errno));
|
|
return EOF;
|
|
}
|
|
free(tun);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int tun_decaps(struct tun_t *tun,
|
|
int (*cb) (void *cl, struct tun_t*, void *pack, unsigned len),
|
|
void *cl)
|
|
{
|
|
unsigned char buffer[PACKET_MAX + 64 /*TODO: ip header */ ];
|
|
int status;
|
|
|
|
|
|
if ((status = read(tun->fd, buffer, sizeof(buffer))) <= 0) {
|
|
syslog(LOG_ERR, "TUN: read(fd=%d,buffer=%lx,len=%d) from network failed: status = %d error = %s",
|
|
tun->fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
|
|
return -1;
|
|
}
|
|
|
|
/* Need to include code to verify packet src and dest addresses */
|
|
return cb(cl, tun, buffer, status);
|
|
}
|
|
|
|
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
|
|
{
|
|
return write(tun->fd, pack, len);
|
|
}
|