9
0
Fork 0
This repository has been archived on 2022-06-17. You can view files and clone it, but cannot push or open issues or pull requests.
openggsn/ggsn/tun.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);
}