add netsimpcap, a network simulation device
[olsrd.git] / contrib / netsimpcap / src / network_tap.c
1 /*
2  * NetsimPcap - a userspace network bridge with simulated packet loss
3  *             Copyright 2008 H. Rogge (rogge@fgan.de)
4  * 
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <pthread.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <signal.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <arpa/inet.h>
30 #include <linux/if_ether.h>
31 #include <linux/if_packet.h>
32 #include <linux/if_tun.h>
33 #include <net/if_arp.h>
34 #include <netinet/ip.h>
35 #include <netinet/udp.h>
36 #include <net/if.h>
37 #include <net/route.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41
42 #include "config.h"
43 #include "debug.h"
44 #include "network_tap.h"
45
46 char macBroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
47
48 /*
49  * This function translates a mac address from string
50  * to binary format.
51  * 
52  * @param pointer to source string
53  * @param pointer to target mac adresee
54  * @return 0 if successful, 1 for an error
55  */
56 int
57 readMac (char *value, MacAddress *target)
58 {
59   char buffer[13];
60   int index = 0;
61   
62   memset(buffer, 0, sizeof(buffer));
63   
64   char c;
65   while ((c = *value++)) {
66     switch (c) {
67     case '0':
68     case '1':
69     case '2':
70     case '3':
71     case '4':
72     case '5':
73     case '6':
74     case '7':
75     case '8':
76     case '9':
77     case 'a':
78     case 'A':
79     case 'b':
80     case 'B':
81     case 'c':
82     case 'C':
83     case 'd':
84     case 'D':
85     case 'e':
86     case 'E':
87     case 'f':
88     case 'F':
89       if (index > 11) {
90         return 1;
91       }
92       buffer[index++] = c;
93       break;
94     default:
95       break;
96     }
97   }
98   
99   if(index < 12) {
100     return 1;
101   }
102   
103   for (index = 5; index >= 0; index--) {
104     buffer[index*2+2] = 0;
105     
106     int value;
107     sscanf(&buffer[index], "%x", &value);
108     target->mac[index] = (char) value;
109   }
110   return 0;
111 }
112
113 /*
114  * closeTap
115  * 
116  * This function close a tap device
117  * 
118  * @param file destriptor of the tap device
119  */
120 void
121 closeTap (int fd)
122 {
123   close(fd);
124 }
125
126 /*
127  * createTap
128  * 
129  * This function creates a tap device, sets a mac address
130  * and the broadcast address and activates the device
131  * 
132  * @param pointer to device name
133  * @param pointer to mac address
134  * @return file descriptor of tap device, -1 if an error
135  * happened
136  */
137 int
138 createTap (char *name, MacAddress *mac)
139 {
140   static const char deviceName[] = "/dev/net/tun";
141   int etfd;
142   struct ifreq ifreq;
143         
144   int ioctlSkfd;
145   int ioctlres;
146         
147   etfd = open(deviceName, O_RDWR);
148   if (etfd < 0) {
149     printf("Cannot open tap device!\n");
150     return -1;
151   }
152         
153   memset(&ifreq, 0, sizeof(ifreq));
154   strncpy(ifreq.ifr_name, name, IFNAMSIZ - 1);
155   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
156         
157         
158   /* Specify the IFF_TAP flag for Ethernet packets.
159    * Specify IFF_NO_PI for not receiving extra meta packet information. */
160   ifreq.ifr_flags = IFF_TAP;
161   ifreq.ifr_flags |= IFF_NO_PI;
162         
163   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0) {
164     close(etfd);
165     printf("Cannot set tun device type!\n");
166     return -1;
167   }
168         
169   memset(&ifreq, 0, sizeof(ifreq));
170   strncpy(ifreq.ifr_name, name, IFNAMSIZ - 1);
171   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
172   ifreq.ifr_addr.sa_family = AF_INET;
173         
174   ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
175   if (ioctlSkfd < 0) {
176     close(etfd);
177     printf("Cannot open configuration socket!\n");
178     return -1;
179   }
180         
181   /* Set hardware address */
182   ifreq.ifr_addr.sa_family = ARPHRD_ETHER;
183   memcpy(ifreq.ifr_addr.sa_data, mac, 6);
184   ioctlres = ioctl(ioctlSkfd, SIOCSIFHWADDR, &ifreq);
185   if (ioctlres >= 0) {
186     /* Set hardware broadcast */
187     memcpy(ifreq.ifr_addr.sa_data, macBroadcast, 6);
188     ioctlres = ioctl(ioctlSkfd, SIOCSIFHWBROADCAST, &ifreq);
189     if (ioctlres >= 0) {
190       /* Bring EtherTunTap interface up (if not already) */
191       ifreq.ifr_addr.sa_family = AF_INET;
192       ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
193       if (ioctlres >= 0) {
194         ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING | IFF_BROADCAST);
195         ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
196       }
197     }
198   }
199   if (ioctlres < 0) {
200     printf("Configuration of tun device failed! (%d %s)\n", errno, strerror(errno));
201     close(etfd);
202     close(ioctlSkfd);
203     return -1;
204   } /* if (ioctlres < 0) */
205         
206         
207   /* Set the multicast flag on the interface */
208   memset(&ifreq, 0, sizeof(ifreq));
209   strncpy(ifreq.ifr_name, name, IFNAMSIZ - 1);
210   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
211         
212   ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
213   if (ioctlres >= 0) {
214     ifreq.ifr_flags |= IFF_MULTICAST;
215     ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
216   }
217         
218   close(ioctlSkfd);
219   return etfd;
220 }
221
222 /*
223  * Local Variables:
224  * c-basic-offset: 2
225  * End:
226  */