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