ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/ether_emu.C
Revision: 1.1
Committed: Thu Oct 16 02:29:25 2003 UTC (20 years, 7 months ago) by pcg
Content type: text/plain
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 ether_emu.C -- ethernet "emulator" library
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "config.h"
20
21 #include <map>
22
23 #include "vpn.h"
24
25 struct ether_emu : map<u32, int> {
26 typedef map<u32, int> ipv4map;
27 ipv4map ipv4;
28
29 bool tun_to_tap (tap_packet *pkt);
30 bool tap_to_tun (tap_packet *pkt);
31
32 void set_ipv4 (u32 ip, int dst)
33 {
34 (ipv4.insert (pair<u32, int>(ip, dst)).first)->second = dst;
35 }
36 };
37
38 static struct ether_emu ether_emu;
39
40 bool
41 ether_emu::tun_to_tap (tap_packet *pkt)
42 {
43 int dst;
44
45 if (pkt->is_ipv4 ())
46 {
47 // update arp cache for _local_ hosts
48 set_ipv4 (pkt->ipv4_src (), THISNODE->id);
49
50 ipv4map::iterator i = ipv4.find (pkt->ipv4_dst ());
51
52 if (i == ipv4.end ())
53 {
54 u32 ip_src = pkt->ipv4_src ();
55 u32 ip_dst = pkt->ipv4_dst ();
56
57 // throw away current packet and make it an arp request
58 (*pkt)[12] = 0x08; (*pkt)[13] = 0x06;
59 (*pkt)[14] = 0x00; (*pkt)[15] = 0x01; // hw
60 (*pkt)[16] = 0x08; (*pkt)[17] = 0x00; // prot
61 (*pkt)[18] = 0x06; // hw_len
62 (*pkt)[19] = 0x04; // prot_len
63 (*pkt)[20] = 0x00; (*pkt)[21] = 0x01; // op
64
65 id2mac (THISNODE->id, &(*pkt)[22]);
66 *(u32 *)&(*pkt)[28] = ip_src;
67 id2mac (0, &(*pkt)[32]);
68 *(u32 *)&(*pkt)[38] = ip_dst;
69
70 pkt->len = 42;
71
72 dst = 0;
73 }
74 else
75 dst = i->second;
76 }
77 else
78 dst = 0; // broadcast non-ip
79
80 id2mac (THISNODE->id, pkt->src);
81 id2mac (dst, pkt->dst);
82
83 return true;
84 }
85
86 bool
87 ether_emu::tap_to_tun (tap_packet *pkt)
88 {
89 if (pkt->is_arp ())
90 {
91 u32 ip_src = *(u32 *)&(*pkt)[28];
92
93 // always update with all info we can get. in this case, the arp sender.
94 set_ipv4 (ip_src, mac2id (&(*pkt)[22]));
95
96 //TODO: remove cache dumper
97 //for (ipv4map::iterator i = ipv4.begin (); i != ipv4.end (); ++i) printf ("%08lx => %d\n", i->first, i->second);
98
99 if ((*pkt)[20] == 0x00 && (*pkt)[21] == 0x01) // arp request
100 {
101 // send a reply, if applicable
102 u32 ip_dst = *(u32 *)&(*pkt)[38];
103 ipv4map::iterator i = ipv4.find (ip_dst);
104
105 // TODO: look up list of local networks and answer for them
106 if (i != ipv4.end () && i->second == THISNODE->id)
107 {
108 // create an arp reply
109 tap_packet *rep = new tap_packet;
110
111 id2mac (THISNODE->id, rep->src);
112 memcpy (rep->dst, pkt->src, sizeof (mac));
113
114 (*rep)[12] = 0x08; (*rep)[13] = 0x06;
115 (*rep)[14] = 0x00; (*rep)[15] = 0x01; // hw
116 (*rep)[16] = 0x08; (*rep)[17] = 0x00; // prot
117 (*rep)[18] = 0x06; // hw_len
118 (*rep)[19] = 0x04; // prot_len
119 (*rep)[20] = 0x00; (*rep)[21] = 0x02; // op
120
121 id2mac (THISNODE->id, &(*rep)[22]);
122 *(u32 *)&(*rep)[28] = ip_dst;
123 memcpy (&(*rep)[32], &(*pkt)[22], sizeof (mac));
124 *(u32 *)&(*rep)[38] = ip_src;
125
126 rep->len = 42;
127
128 network.inject_data_packet (rep, mac2id (rep->dst));
129
130 delete rep;
131 }
132 }
133 else if ((*pkt)[20] == 0x00 && (*pkt)[21] == 0x02) // arp reply
134 set_ipv4 (*(u32 *)&(*pkt)[28], mac2id (&(*pkt)[22]));
135
136 return false;
137 }
138 else if (pkt->is_ipv4 ())
139 {
140 // update arp cache
141 set_ipv4 (pkt->ipv4_src (), mac2id (pkt->src));
142 set_ipv4 (pkt->ipv4_dst (), mac2id (pkt->dst));
143 }
144
145 return true;
146 }
147