aboutsummaryrefslogtreecommitdiffstats
path: root/ggsn/tun.c
blob: 72ea2640609549736c0b63f5009201d66ba34cbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* 
 *  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);
}