2 * 802.1q vlan -> eoip tagging gateway
3 * (c) 2008-2011 Karel Tuma <karel.tuma@pilsfree.net>
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 2, or (at your option)
10 * You should have received a copy of the GNU General Public License
11 * (for example /usr/src/linux/COPYING); if not, write to the Free
12 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
25 #include <linux/if_tun.h>
31 #include <netinet/ip.h>
32 #include <arpa/inet.h>
34 #define max(a,b) ((a)>(b) ? (a):(b))
41 #define LOG(msg...) {printf(msg); printf("\n");}
44 #define GREHDR "\x20\x01\x64\x00"
54 static int opentun(int flags
, char *name
)
57 int fd
= open("/dev/net/tun", O_RDWR
);
59 memset(&ifr
,0,sizeof(ifr
));
60 ifr
.ifr_flags
= flags
;
61 strncpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
62 // write(2, &ifr, sizeof(ifr));
63 ioctl(fd
, TUNSETIFF
, (void *) &ifr
);
64 // ioctl(fd, TUNSETPERSIST, 1);
71 "%s <intf> <localip> <remoteip - eoip target> [ignored vlan ids]\n",a0
);
76 int main(int argc
, char *argv
[])
79 unsigned char ignore
[4096];
83 memset(ignore
,0,sizeof(ignore
));
84 for (i
= 3; i
< argc
; i
++)
85 ignore
[atoi(argv
[i
])]=1;
88 struct sockaddr_in sin
;
97 fdtap
= opentun(IFF_TAP
|IFF_NO_PI
, argv
[1]);
98 locip
= inet_addr(argv
[2]);
99 remip
= inet_addr(argv
[3]);
102 fdraw
= socket(AF_INET
, SOCK_RAW
, 47);
103 sin
.sin_family
= AF_INET
;
104 sin
.sin_addr
.s_addr
= locip
;
105 sin
.sin_port
= htons(47);
106 assert(bind(fdraw
, (struct sockaddr
*)&sin
, sizeof(sin
))==0);
109 memset(&sin
, 0, sizeof(sin
));
110 sin
.sin_family
= AF_INET
;
111 sin
.sin_addr
.s_addr
= remip
;
115 ioctl(fdtap
, TUNSETNOCSUM
, 1);
130 select(max(fdtap
,fdraw
)+1,&fds
,NULL
,NULL
,&tv
);
132 /* got mtk GRE packet */
133 if (FD_ISSET(fdraw
, &fds
)) {
134 len
= recv(fdraw
, pkt
.buf
, sizeof(pkt
), 0);
137 if (pkt
.ip
.daddr
!= locip
) continue;
138 if (pkt
.ip
.saddr
!= remip
) continue;
140 /* move past ip header */
141 p
= pkt
.buf
+ pkt
.ip
.ihl
*4; len
-= pkt
.ip
.ihl
*4;
142 DEBUG("len is=%d\n", len
);
144 /* check its really eoip */
145 if (memcmp(p
, GREHDR
, GREHDRSZ
)) continue;
147 /* move past header */
150 if (len
< 0) continue;
152 tid
= ((uint16_t *) p
)[-1]; /* tunnel id, actually 802.1q tag number */
153 if (tid
> 4095) continue;
154 if (ignore
[tid
]) continue;
156 /* IP hdr/eoip length mismatch */
157 if (len
!= ntohs(((uint16_t*)p
)[-2])) {
158 DEBUG("%d %d\n",len
,ntohs(((uint16_t*)p
)[-2]));
163 DEBUG("len=%d\n",len
);
164 for (i
= 0; i
< len
; i
++) DEBUG("%02hhx ", p
[i
]);
167 /* shift src/dst mac by 4 bytes */
169 p
[12-4] = 0x81; p
[13-4] = 0x00;
170 p
[14-4] = /*0x40 | */(tid
>>8);
171 p
[15-4] = tid
& 0xff;
172 write(fdtap
, p
-4, len
+4);
177 if (FD_ISSET(fdtap
, &fds
)) {
179 struct gre_packet gre
;
180 uint8_t mybuf
[65536];
184 len
= read(fdtap
, p
, sizeof(pkt
));
186 if (len
<= 16) continue;
187 /* only tagged packets please */
188 if (p
[12] != 0x81 || p
[13] != 0x00) continue;
189 tid
= ((p
[14] << 8)&0xf00) | p
[15];
190 if (ignore
[tid
]) continue;
191 memcpy(sbuf
.gre
.data
, p
, 12); /* src & dst mac */
192 memcpy(sbuf
.gre
.data
+ 12, p
+ 16, len
-16); /* skip the tag */
194 sin
.sin_port
= htons(47);
195 memcpy(sbuf
.gre
.magic
, GREHDR
, GREHDRSZ
);
196 sbuf
.gre
.len
= htons(len
- 4);
197 sbuf
.gre
.tid
= tid
; /* little endian! */
198 sendto(fdraw
, sbuf
.mybuf
, len
+8-4, 0, (struct sockaddr
*) &sin
, sizeof(sin
));