if_gre.c revision 1.7.2.1 1 1.7.2.1 perry /* $NetBSD: if_gre.c,v 1.7.2.1 1999/07/02 16:36:35 perry Exp $ */
2 1.4 thorpej
3 1.1 hwr /*
4 1.4 thorpej * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 1.1 hwr * All rights reserved.
6 1.1 hwr *
7 1.1 hwr * This code is derived from software contributed to The NetBSD Foundation
8 1.1 hwr * by Heiko W.Rupp <hwr (at) pilhuhn.de>
9 1.1 hwr *
10 1.1 hwr * Redistribution and use in source and binary forms, with or without
11 1.1 hwr * modification, are permitted provided that the following conditions
12 1.1 hwr * are met:
13 1.1 hwr * 1. Redistributions of source code must retain the above copyright
14 1.1 hwr * notice, this list of conditions and the following disclaimer.
15 1.1 hwr * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 hwr * notice, this list of conditions and the following disclaimer in the
17 1.1 hwr * documentation and/or other materials provided with the distribution.
18 1.1 hwr * 3. All advertising materials mentioning features or use of this software
19 1.1 hwr * must display the following acknowledgement:
20 1.1 hwr * This product includes software developed by the NetBSD
21 1.1 hwr * Foundation, Inc. and its contributors.
22 1.1 hwr * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 hwr * contributors may be used to endorse or promote products derived
24 1.1 hwr * from this software without specific prior written permission.
25 1.1 hwr *
26 1.1 hwr * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 hwr * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 hwr * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 hwr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 hwr * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 hwr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 hwr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 hwr * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 hwr * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 hwr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 hwr * POSSIBILITY OF SUCH DAMAGE.
37 1.1 hwr */
38 1.1 hwr
39 1.1 hwr /*
40 1.1 hwr * Encapsulate L3 protocols into IP
41 1.1 hwr * See RFC 1701 and 1702 for more details.
42 1.1 hwr * If_gre is compatible with Cisco GRE tunnels, so you can
43 1.1 hwr * have a NetBSD box as the other end of a tunnel interface of a Cisco
44 1.1 hwr * router. See gre(4) for more details.
45 1.6 hwr * Also supported: IP in IP encaps (proto 55) as of RFC 2004
46 1.1 hwr */
47 1.1 hwr
48 1.1 hwr #include "gre.h"
49 1.1 hwr #if NGRE > 0
50 1.1 hwr
51 1.1 hwr #include "opt_inet.h"
52 1.1 hwr #include "bpfilter.h"
53 1.1 hwr
54 1.1 hwr #include <sys/param.h>
55 1.1 hwr #include <sys/proc.h>
56 1.1 hwr #include <sys/malloc.h>
57 1.1 hwr #include <sys/mbuf.h>
58 1.1 hwr #include <sys/buf.h>
59 1.1 hwr #include <sys/dkstat.h>
60 1.1 hwr #include <sys/protosw.h>
61 1.1 hwr #include <sys/socket.h>
62 1.1 hwr #include <sys/ioctl.h>
63 1.1 hwr #include <sys/sockio.h>
64 1.1 hwr #include <sys/file.h>
65 1.1 hwr #include <sys/tty.h>
66 1.1 hwr #include <sys/kernel.h>
67 1.1 hwr #include <sys/conf.h>
68 1.1 hwr #if __NetBSD__
69 1.1 hwr #include <sys/systm.h>
70 1.1 hwr #endif
71 1.1 hwr
72 1.1 hwr #include <machine/cpu.h>
73 1.1 hwr
74 1.1 hwr #include <net/ethertypes.h>
75 1.1 hwr #include <net/if.h>
76 1.1 hwr #include <net/if_types.h>
77 1.1 hwr #include <net/netisr.h>
78 1.1 hwr #include <net/route.h>
79 1.1 hwr
80 1.1 hwr #ifdef INET
81 1.1 hwr #include <netinet/in.h>
82 1.1 hwr #include <netinet/in_systm.h>
83 1.1 hwr #include <netinet/in_var.h>
84 1.1 hwr #include <netinet/ip.h>
85 1.1 hwr #include <netinet/ip_var.h>
86 1.1 hwr #else
87 1.4 thorpej #error "Huh? if_gre without inet?"
88 1.1 hwr #endif
89 1.1 hwr
90 1.1 hwr #ifdef NS
91 1.1 hwr #include <netns/ns.h>
92 1.1 hwr #include <netns/ns_if.h>
93 1.1 hwr #endif
94 1.1 hwr
95 1.1 hwr #ifdef NETATALK
96 1.1 hwr #include <netatalk/at.h>
97 1.1 hwr #include <netatalk/at_var.h>
98 1.1 hwr #include <netatalk/at_extern.h>
99 1.1 hwr #endif
100 1.1 hwr
101 1.1 hwr #if NBPFILTER > 0
102 1.1 hwr #include <sys/time.h>
103 1.1 hwr #include <net/bpf.h>
104 1.1 hwr #endif
105 1.1 hwr
106 1.1 hwr #include <net/if_gre.h>
107 1.1 hwr
108 1.1 hwr #define GREMTU 1450 /* XXX this is below the standard MTU of
109 1.1 hwr 1500 Bytes, allowing for headers,
110 1.1 hwr but we should possibly do path mtu discovery
111 1.1 hwr before changing if state to up to find the
112 1.1 hwr correct value */
113 1.3 hwr #define LINK_MASK (IFF_LINK0|IFF_LINK1|IFF_LINK2)
114 1.1 hwr
115 1.1 hwr struct gre_softc gre_softc[NGRE];
116 1.1 hwr
117 1.1 hwr
118 1.1 hwr void gre_compute_route(struct gre_softc *sc);
119 1.1 hwr #ifdef DIAGNOSTIC
120 1.3 hwr void gre_inet_ntoa(struct in_addr in);
121 1.1 hwr #endif
122 1.1 hwr
123 1.7.2.1 perry void
124 1.7.2.1 perry greattach(void)
125 1.1 hwr {
126 1.7.2.1 perry struct gre_softc *sc;
127 1.7.2.1 perry int i;
128 1.1 hwr
129 1.1 hwr i = 0 ;
130 1.7.2.1 perry for (sc = gre_softc ; i < NGRE ; sc++ ) {
131 1.1 hwr sprintf(sc->sc_if.if_xname, "gre%d", i++);
132 1.1 hwr sc->sc_if.if_softc = sc;
133 1.1 hwr sc->sc_if.if_type = IFT_OTHER;
134 1.1 hwr sc->sc_if.if_addrlen = 4;
135 1.1 hwr sc->sc_if.if_hdrlen = 24; /* IP + GRE */
136 1.1 hwr sc->sc_if.if_mtu = GREMTU;
137 1.1 hwr sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
138 1.1 hwr sc->sc_if.if_output = gre_output;
139 1.1 hwr sc->sc_if.if_ioctl = gre_ioctl;
140 1.7.2.1 perry sc->sc_if.if_collisions = 0;
141 1.7.2.1 perry sc->sc_if.if_ierrors = 0;
142 1.7.2.1 perry sc->sc_if.if_oerrors = 0;
143 1.7.2.1 perry sc->sc_if.if_ipackets = 0;
144 1.7.2.1 perry sc->sc_if.if_opackets = 0;
145 1.7.2.1 perry sc->g_dst.s_addr = sc->g_src.s_addr=INADDR_ANY;
146 1.7.2.1 perry sc->g_proto = IPPROTO_GRE;
147 1.1 hwr if_attach(&sc->sc_if);
148 1.1 hwr #if 0
149 1.1 hwr #if NBPFILTER > 0
150 1.6 hwr bpfattach(&sc->gre_bpf, &sc->sc_if, DLT_RAW, sizeof(u_int32_t) );
151 1.1 hwr #endif
152 1.1 hwr #endif
153 1.1 hwr
154 1.1 hwr }
155 1.1 hwr }
156 1.1 hwr
157 1.1 hwr
158 1.1 hwr /*
159 1.1 hwr * The output routine. Takes a packet and encapsulates it in the protocol
160 1.6 hwr * given by sc->g_proto. See also RFC 1701 and RFC 2004
161 1.1 hwr */
162 1.1 hwr
163 1.7.2.1 perry #if 0
164 1.1 hwr struct ip ip_h;
165 1.7.2.1 perry #endif
166 1.3 hwr struct mobile_h mob_h;
167 1.1 hwr
168 1.1 hwr int
169 1.7.2.1 perry gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
170 1.7.2.1 perry struct rtentry *rt)
171 1.1 hwr {
172 1.7.2.1 perry int error = 0;
173 1.7.2.1 perry struct gre_softc *sc = (struct gre_softc *)(ifp->if_softc);
174 1.1 hwr struct greip *gh;
175 1.1 hwr struct ip *inp;
176 1.7.2.1 perry u_char ttl, osrc;
177 1.7.2.1 perry u_short etype = 0;
178 1.3 hwr
179 1.1 hwr
180 1.7.2.1 perry gh = NULL;
181 1.7.2.1 perry inp = NULL;
182 1.7.2.1 perry osrc = 0;
183 1.1 hwr
184 1.1 hwr #if 0
185 1.1 hwr #if NBPFILTER >0
186 1.1 hwr
187 1.1 hwr if (sc->gre_bpf) {
188 1.1 hwr /* see comment of other if_foo.c files */
189 1.1 hwr struct mbuf m0;
190 1.1 hwr u_int af = dst->sa_family;
191 1.1 hwr
192 1.7.2.1 perry m0.m_next = m;
193 1.7.2.1 perry m0.m_len = 4;
194 1.1 hwr m0.m_data = (char *)⁡
195 1.1 hwr
196 1.1 hwr bpf_mtap(ifp->if_bpf, &m0);
197 1.1 hwr }
198 1.1 hwr #endif
199 1.1 hwr #endif
200 1.1 hwr
201 1.7.2.1 perry ttl = 255;
202 1.1 hwr
203 1.5 thorpej if (sc->g_proto == IPPROTO_MOBILE) {
204 1.3 hwr if (dst->sa_family == AF_INET) {
205 1.3 hwr struct mbuf *m0;
206 1.3 hwr int msiz;
207 1.3 hwr
208 1.7.2.1 perry inp = mtod(m, struct ip *);
209 1.3 hwr
210 1.7.2.1 perry memset(&mob_h, 0, MOB_H_SIZ_L);
211 1.7.2.1 perry mob_h.proto = (inp->ip_p) << 8;
212 1.7.2.1 perry mob_h.odst = inp->ip_dst.s_addr;
213 1.7.2.1 perry inp->ip_dst.s_addr = sc->g_dst.s_addr;
214 1.3 hwr
215 1.3 hwr /*
216 1.7.2.1 perry * If the packet comes from our host, we only change
217 1.7.2.1 perry * the destination address in the IP header.
218 1.7.2.1 perry * Else we also need to save and change the source
219 1.3 hwr */
220 1.3 hwr if (in_hosteq(inp->ip_src, sc->g_src)) {
221 1.7.2.1 perry msiz = MOB_H_SIZ_S;
222 1.3 hwr } else {
223 1.3 hwr mob_h.proto |= MOB_H_SBIT;
224 1.7.2.1 perry mob_h.osrc = inp->ip_src.s_addr;
225 1.7.2.1 perry inp->ip_src.s_addr = sc->g_src.s_addr;
226 1.7.2.1 perry msiz = MOB_H_SIZ_L;
227 1.3 hwr }
228 1.3 hwr HTONS(mob_h.proto);
229 1.7.2.1 perry mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
230 1.3 hwr
231 1.3 hwr if ((m->m_data - msiz) < m->m_pktdat) {
232 1.3 hwr /* need new mbuf */
233 1.3 hwr MGETHDR(m0, M_DONTWAIT, MT_HEADER);
234 1.7.2.1 perry if (m0 == NULL) {
235 1.3 hwr IF_DROP(&ifp->if_snd);
236 1.3 hwr m_freem(m);
237 1.7.2.1 perry return (ENOBUFS);
238 1.3 hwr }
239 1.7.2.1 perry m0->m_next = m;
240 1.3 hwr m->m_data += sizeof(struct ip);
241 1.3 hwr m->m_len -= sizeof(struct ip);
242 1.7.2.1 perry m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
243 1.3 hwr m0->m_len = msiz + sizeof(struct ip);
244 1.3 hwr m0->m_data += max_linkhdr;
245 1.7.2.1 perry memcpy(mtod(m0, caddr_t), (caddr_t)inp,
246 1.7.2.1 perry sizeof(struct ip));
247 1.7.2.1 perry m = m0;
248 1.7.2.1 perry } else { /* we have some spave left in the old one */
249 1.7.2.1 perry m->m_data -= msiz;
250 1.7.2.1 perry m->m_len += msiz;
251 1.7.2.1 perry m->m_pkthdr.len += msiz;
252 1.7.2.1 perry memmove(mtod(m, caddr_t), inp,
253 1.7.2.1 perry sizeof(struct ip));
254 1.3 hwr }
255 1.7.2.1 perry inp=mtod(m, struct ip *);
256 1.7.2.1 perry memcpy((caddr_t)(inp + 1), &mob_h, (unsigned)msiz);
257 1.3 hwr NTOHS(inp->ip_len);
258 1.7.2.1 perry inp->ip_len += msiz;
259 1.3 hwr } else { /* AF_INET */
260 1.3 hwr IF_DROP(&ifp->if_snd);
261 1.3 hwr m_freem(m);
262 1.7.2.1 perry return (EINVAL);
263 1.3 hwr }
264 1.1 hwr } else if (sc->g_proto == IPPROTO_GRE) {
265 1.1 hwr switch(dst->sa_family) {
266 1.1 hwr case AF_INET:
267 1.7.2.1 perry inp = mtod(m, struct ip *);
268 1.7.2.1 perry ttl = inp->ip_ttl;
269 1.7.2.1 perry etype = ETHERTYPE_IP;
270 1.1 hwr break;
271 1.1 hwr #ifdef NETATALK
272 1.1 hwr case AF_APPLETALK:
273 1.7.2.1 perry etype = ETHERTYPE_ATALK;
274 1.1 hwr break;
275 1.1 hwr #endif
276 1.1 hwr #ifdef NS
277 1.1 hwr case AF_NS:
278 1.7.2.1 perry etype = ETHERTYPE_NS;
279 1.1 hwr break;
280 1.1 hwr #endif
281 1.1 hwr default:
282 1.1 hwr IF_DROP(&ifp->if_snd);
283 1.1 hwr m_freem(m);
284 1.7.2.1 perry return (EAFNOSUPPORT);
285 1.1 hwr }
286 1.7.2.1 perry M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
287 1.1 hwr } else {
288 1.7.2.1 perry error = EINVAL;
289 1.1 hwr IF_DROP(&ifp->if_snd);
290 1.1 hwr m_freem(m);
291 1.7.2.1 perry return (error);
292 1.1 hwr }
293 1.1 hwr
294 1.1 hwr
295 1.1 hwr if (m == NULL) {
296 1.1 hwr IF_DROP(&ifp->if_snd);
297 1.7.2.1 perry return (ENOBUFS);
298 1.1 hwr }
299 1.1 hwr
300 1.7.2.1 perry gh = mtod(m, struct greip *);
301 1.7.2.1 perry if (sc->g_proto == IPPROTO_GRE) {
302 1.1 hwr /* we don't have any GRE flags for now */
303 1.1 hwr
304 1.7.2.1 perry memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
305 1.7.2.1 perry gh->gi_ptype = htons(etype);
306 1.1 hwr }
307 1.1 hwr
308 1.1 hwr gh->gi_pr = sc->g_proto;
309 1.3 hwr if (sc->g_proto != IPPROTO_MOBILE) {
310 1.3 hwr gh->gi_src = sc->g_src;
311 1.3 hwr gh->gi_dst = sc->g_dst;
312 1.3 hwr ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
313 1.7.2.1 perry ((struct ip*)gh)->ip_ttl = ttl;
314 1.7.2.1 perry ((struct ip*)gh)->ip_tos = inp->ip_tos;
315 1.3 hwr gh->gi_len = m->m_pkthdr.len;
316 1.3 hwr }
317 1.1 hwr
318 1.1 hwr ifp->if_opackets++;
319 1.7.2.1 perry ifp->if_obytes += m->m_pkthdr.len;
320 1.1 hwr /* send it off */
321 1.7.2.1 perry error = ip_output(m, NULL, &sc->route, 0, NULL);
322 1.7.2.1 perry if (error)
323 1.1 hwr ifp->if_oerrors++;
324 1.7.2.1 perry return (error);
325 1.1 hwr
326 1.1 hwr }
327 1.1 hwr
328 1.1 hwr int
329 1.7.2.1 perry gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
330 1.1 hwr {
331 1.1 hwr
332 1.7.2.1 perry struct ifaddr *ifa = (struct ifaddr *)data;
333 1.7.2.1 perry struct ifreq *ifr = (struct ifreq *)data;
334 1.7.2.1 perry struct in_ifaddr *ia = (struct in_ifaddr *)data;
335 1.7.2.1 perry struct gre_softc *sc = ifp->if_softc;
336 1.1 hwr int s;
337 1.1 hwr struct sockaddr_in si;
338 1.7.2.1 perry struct sockaddr *sa = NULL;
339 1.1 hwr int error;
340 1.1 hwr
341 1.7.2.1 perry error = 0;
342 1.1 hwr
343 1.1 hwr s = splimp();
344 1.1 hwr switch(cmd) {
345 1.1 hwr case SIOCSIFADDR:
346 1.1 hwr case SIOCSIFDSTADDR:
347 1.1 hwr /*
348 1.1 hwr * set tunnel endpoints in case that we "only"
349 1.1 hwr * have ip over ip encapsulation. This allows to
350 1.1 hwr * set tunnel endpoints with ifconfig.
351 1.1 hwr */
352 1.1 hwr if (ifa->ifa_addr->sa_family == AF_INET) {
353 1.1 hwr sa = ifa->ifa_addr;
354 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
355 1.1 hwr sc->g_dst = ia->ia_dstaddr.sin_addr;
356 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
357 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
358 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
359 1.1 hwr RTFREE(sc->route.ro_rt);
360 1.1 hwr gre_compute_route(sc);
361 1.1 hwr ifp->if_flags |= IFF_UP;
362 1.1 hwr }
363 1.1 hwr }
364 1.1 hwr break;
365 1.1 hwr case SIOCSIFFLAGS:
366 1.7.2.1 perry if ((sc->g_dst.s_addr == INADDR_ANY) ||
367 1.7.2.1 perry (sc->g_src.s_addr == INADDR_ANY))
368 1.1 hwr ifp->if_flags &= ~IFF_UP;
369 1.1 hwr
370 1.3 hwr switch(ifr->ifr_flags & LINK_MASK) {
371 1.3 hwr case IFF_LINK0:
372 1.3 hwr sc->g_proto = IPPROTO_GRE;
373 1.3 hwr ifp->if_flags |= IFF_LINK0;
374 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
375 1.3 hwr break;
376 1.3 hwr case IFF_LINK2:
377 1.3 hwr sc->g_proto = IPPROTO_MOBILE;
378 1.3 hwr ifp->if_flags |= IFF_LINK2;
379 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1);
380 1.3 hwr break;
381 1.1 hwr }
382 1.1 hwr break;
383 1.1 hwr case SIOCSIFMTU:
384 1.1 hwr if (ifr->ifr_mtu > GREMTU || ifr->ifr_mtu < 576) {
385 1.1 hwr error = EINVAL;
386 1.1 hwr break;
387 1.1 hwr }
388 1.1 hwr ifp->if_mtu = ifr->ifr_mtu;
389 1.1 hwr break;
390 1.1 hwr case SIOCGIFMTU:
391 1.1 hwr ifr->ifr_mtu = sc->sc_if.if_mtu;
392 1.1 hwr break;
393 1.1 hwr case SIOCADDMULTI:
394 1.1 hwr case SIOCDELMULTI:
395 1.7.2.1 perry if (ifr == 0) {
396 1.1 hwr error = EAFNOSUPPORT;
397 1.1 hwr break;
398 1.1 hwr }
399 1.7.2.1 perry switch (ifr->ifr_addr.sa_family) {
400 1.1 hwr #ifdef INET
401 1.1 hwr case AF_INET:
402 1.1 hwr break;
403 1.1 hwr #endif
404 1.1 hwr default:
405 1.1 hwr error = EAFNOSUPPORT;
406 1.1 hwr break;
407 1.1 hwr }
408 1.1 hwr break;
409 1.1 hwr case GRESPROTO:
410 1.1 hwr sc->g_proto = ifr->ifr_flags;
411 1.1 hwr switch (sc->g_proto) {
412 1.3 hwr case IPPROTO_GRE :
413 1.3 hwr ifp->if_flags |= IFF_LINK0;
414 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
415 1.1 hwr break;
416 1.3 hwr case IPPROTO_MOBILE :
417 1.3 hwr ifp->if_flags |= IFF_LINK2;
418 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
419 1.1 hwr break;
420 1.1 hwr default:
421 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
422 1.1 hwr }
423 1.1 hwr break;
424 1.1 hwr case GREGPROTO:
425 1.1 hwr ifr->ifr_flags = sc->g_proto;
426 1.1 hwr break;
427 1.1 hwr case GRESADDRS:
428 1.1 hwr case GRESADDRD:
429 1.1 hwr /*
430 1.1 hwr * set tunnel endpoints, compute a less specific route
431 1.1 hwr * to the remote end and mark if as up
432 1.1 hwr */
433 1.1 hwr sa = &ifr->ifr_addr;
434 1.1 hwr if (cmd == GRESADDRS )
435 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
436 1.1 hwr if (cmd == GRESADDRD )
437 1.1 hwr sc->g_dst = (satosin(sa))->sin_addr;
438 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
439 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
440 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
441 1.1 hwr RTFREE(sc->route.ro_rt);
442 1.1 hwr gre_compute_route(sc);
443 1.1 hwr ifp->if_flags |= IFF_UP;
444 1.1 hwr }
445 1.1 hwr break;
446 1.1 hwr case GREGADDRS:
447 1.1 hwr si.sin_addr.s_addr = sc->g_src.s_addr;
448 1.7.2.1 perry sa = sintosa(&si);
449 1.1 hwr ifr->ifr_addr = *sa;
450 1.1 hwr break;
451 1.1 hwr case GREGADDRD:
452 1.1 hwr si.sin_addr.s_addr = sc->g_dst.s_addr;
453 1.7.2.1 perry sa = sintosa(&si);
454 1.1 hwr ifr->ifr_addr = *sa;
455 1.1 hwr break;
456 1.1 hwr default:
457 1.1 hwr error = EINVAL;
458 1.1 hwr }
459 1.1 hwr
460 1.1 hwr splx(s);
461 1.7.2.1 perry return (error);
462 1.1 hwr }
463 1.1 hwr
464 1.1 hwr /*
465 1.1 hwr * computes a route to our destination that is not the one
466 1.1 hwr * which would be taken by ip_output(), as this one will loop back to
467 1.1 hwr * us. If the interface is p2p as a--->b, then a routing entry exists
468 1.1 hwr * If we now send a packet to b (e.g. ping b), this will come down here
469 1.1 hwr * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
470 1.1 hwr * if_gre.
471 1.1 hwr * Goal here is to compute a route to b that is less specific than
472 1.1 hwr * a-->b. We know that this one exists as in normal operation we have
473 1.1 hwr * at least a default route which matches.
474 1.1 hwr */
475 1.1 hwr
476 1.7.2.1 perry void
477 1.7.2.1 perry gre_compute_route(struct gre_softc *sc)
478 1.1 hwr {
479 1.1 hwr struct route *ro;
480 1.7.2.1 perry u_int32_t a, b, c;
481 1.1 hwr
482 1.7.2.1 perry ro = &sc->route;
483 1.1 hwr
484 1.7.2.1 perry memset(ro, 0, sizeof(struct route));
485 1.7.2.1 perry ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
486 1.7.2.1 perry ro->ro_dst.sa_family = AF_INET;
487 1.7.2.1 perry ro->ro_dst.sa_len = sizeof(ro->ro_dst);
488 1.7.2.1 perry
489 1.1 hwr /*
490 1.1 hwr * toggle last bit, so our interface is not found, but a less
491 1.1 hwr * specific route. I'd rather like to specify a shorter mask,
492 1.1 hwr * but this is not possible. Should work though. XXX
493 1.1 hwr * there is a simpler way ...
494 1.1 hwr */
495 1.7.2.1 perry if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
496 1.7.2.1 perry a = ntohl(sc->g_dst.s_addr);
497 1.7.2.1 perry b = a & 0x01;
498 1.7.2.1 perry c = a & 0xfffffffe;
499 1.7.2.1 perry b = b ^ 0x01;
500 1.7.2.1 perry a = b | c;
501 1.7.2.1 perry ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
502 1.7.2.1 perry = htonl(a);
503 1.7.2.1 perry }
504 1.1 hwr
505 1.1 hwr #ifdef DIAGNOSTIC
506 1.7.2.1 perry printf("%s: searching a route to ", sc->sc_if.if_xname);
507 1.7.2.1 perry gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
508 1.1 hwr #endif
509 1.1 hwr
510 1.1 hwr rtalloc(ro);
511 1.1 hwr
512 1.1 hwr /*
513 1.1 hwr * now change it back - else ip_output will just drop
514 1.1 hwr * the route and search one to this interface ...
515 1.1 hwr */
516 1.7.2.1 perry if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
517 1.7.2.1 perry ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
518 1.1 hwr
519 1.1 hwr #ifdef DIAGNOSTIC
520 1.7.2.1 perry printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
521 1.7.2.1 perry gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
522 1.7.2.1 perry printf("\n");
523 1.1 hwr #endif
524 1.1 hwr }
525 1.1 hwr
526 1.3 hwr /*
527 1.3 hwr * do a checksum of a buffer - much like in_cksum, which operates on
528 1.3 hwr * mbufs.
529 1.3 hwr */
530 1.3 hwr
531 1.3 hwr u_short
532 1.7.2.1 perry gre_in_cksum(u_short *p, u_int len)
533 1.3 hwr {
534 1.3 hwr u_int sum = 0;
535 1.3 hwr int nwords = len >> 1;
536 1.3 hwr
537 1.3 hwr while (nwords-- != 0)
538 1.3 hwr sum += *p++;
539 1.3 hwr
540 1.3 hwr if (len & 1) {
541 1.3 hwr union {
542 1.3 hwr u_short w;
543 1.3 hwr u_char c[2];
544 1.3 hwr } u;
545 1.3 hwr u.c[0] = *(u_char *)p;
546 1.3 hwr u.c[1] = 0;
547 1.3 hwr sum += u.w;
548 1.3 hwr }
549 1.3 hwr
550 1.3 hwr /* end-around-carry */
551 1.3 hwr sum = (sum >> 16) + (sum & 0xffff);
552 1.3 hwr sum += (sum >> 16);
553 1.3 hwr return (~sum);
554 1.3 hwr }
555 1.3 hwr
556 1.3 hwr
557 1.1 hwr /* while testing ... */
558 1.1 hwr #ifdef DIAGNOSTIC
559 1.1 hwr void
560 1.7.2.1 perry gre_inet_ntoa(struct in_addr in)
561 1.1 hwr {
562 1.7.2.1 perry char *p;
563 1.1 hwr
564 1.7.2.1 perry p = (char *)∈
565 1.1 hwr #define UC(b) (((int)b)&0xff)
566 1.7.2.1 perry printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
567 1.1 hwr }
568 1.1 hwr
569 1.1 hwr #endif
570 1.1 hwr #endif
571 1.1 hwr
572