/* * 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 * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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); }