Deleted Added
full compact
if_gre.c (103026) if_gre.c (103032)
1/* $NetBSD: if_gre.c,v 1.42 2002/08/14 00:23:27 itojun Exp $ */
1/* $NetBSD: if_gre.c,v 1.42 2002/08/14 00:23:27 itojun Exp $ */
2/* $FreeBSD: head/sys/net/if_gre.c 103026 2002-09-06 17:12:50Z sobomax $ */
2/* $FreeBSD: head/sys/net/if_gre.c 103032 2002-09-06 18:16:03Z sobomax $ */
3
4/*
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Heiko W.Rupp <hwr@pilhuhn.de>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * Encapsulate L3 protocols into IP
42 * See RFC 1701 and 1702 for more details.
43 * If_gre is compatible with Cisco GRE tunnels, so you can
44 * have a NetBSD box as the other end of a tunnel interface of a Cisco
45 * router. See gre(4) for more details.
46 * Also supported: IP in IP encaps (proto 55) as of RFC 2004
47 */
48
49#include <sys/cdefs.h>
3
4/*
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Heiko W.Rupp <hwr@pilhuhn.de>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * Encapsulate L3 protocols into IP
42 * See RFC 1701 and 1702 for more details.
43 * If_gre is compatible with Cisco GRE tunnels, so you can
44 * have a NetBSD box as the other end of a tunnel interface of a Cisco
45 * router. See gre(4) for more details.
46 * Also supported: IP in IP encaps (proto 55) as of RFC 2004
47 */
48
49#include <sys/cdefs.h>
50__RCSID("@(#) $FreeBSD: head/sys/net/if_gre.c 103026 2002-09-06 17:12:50Z sobomax $");
50__RCSID("@(#) $FreeBSD: head/sys/net/if_gre.c 103032 2002-09-06 18:16:03Z sobomax $");
51
52#include "opt_inet.h"
53#include "opt_ns.h"
54#include "bpf.h"
55
56#include <sys/param.h>
57#include <sys/kernel.h>
58#include <sys/malloc.h>
59#include <sys/mbuf.h>
60#include <sys/proc.h>
61#include <sys/protosw.h>
62#include <sys/socket.h>
63#include <sys/sockio.h>
64#include <sys/queue.h>
65#include <sys/sysctl.h>
66
67#include <machine/cpu.h>
68
69#include <net/ethernet.h>
70#include <net/if.h>
71#include <net/if_types.h>
72#include <net/netisr.h>
73#include <net/route.h>
74
75#ifdef INET
76#include <netinet/in.h>
77#include <netinet/in_systm.h>
78#include <netinet/in_var.h>
79#include <netinet/ip.h>
80#include <netinet/ip_gre.h>
81#include <netinet/ip_var.h>
82#include <netinet/ip_encap.h>
83#else
84#error "Huh? if_gre without inet?"
85#endif
86
87#ifdef NS
88#include <netns/ns.h>
89#include <netns/ns_if.h>
90#endif
91
92#ifdef NETATALK
93#include <netatalk/at.h>
94#include <netatalk/at_var.h>
95#include <netatalk/at_extern.h>
96#endif
97
98#if NBPF > 0
99#include <sys/time.h>
100#include <net/bpf.h>
101#endif
102
103#include <net/net_osdep.h>
104#include <net/if_gre.h>
105
106/*
107 * It is not easy to calculate the right value for a GRE MTU.
108 * We leave this task to the admin and use the same default that
109 * other vendors use.
110 */
111#define GREMTU 1476
112
113#define GRENAME "gre"
114
115static MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation");
116
117struct gre_softc_head gre_softc_list;
51
52#include "opt_inet.h"
53#include "opt_ns.h"
54#include "bpf.h"
55
56#include <sys/param.h>
57#include <sys/kernel.h>
58#include <sys/malloc.h>
59#include <sys/mbuf.h>
60#include <sys/proc.h>
61#include <sys/protosw.h>
62#include <sys/socket.h>
63#include <sys/sockio.h>
64#include <sys/queue.h>
65#include <sys/sysctl.h>
66
67#include <machine/cpu.h>
68
69#include <net/ethernet.h>
70#include <net/if.h>
71#include <net/if_types.h>
72#include <net/netisr.h>
73#include <net/route.h>
74
75#ifdef INET
76#include <netinet/in.h>
77#include <netinet/in_systm.h>
78#include <netinet/in_var.h>
79#include <netinet/ip.h>
80#include <netinet/ip_gre.h>
81#include <netinet/ip_var.h>
82#include <netinet/ip_encap.h>
83#else
84#error "Huh? if_gre without inet?"
85#endif
86
87#ifdef NS
88#include <netns/ns.h>
89#include <netns/ns_if.h>
90#endif
91
92#ifdef NETATALK
93#include <netatalk/at.h>
94#include <netatalk/at_var.h>
95#include <netatalk/at_extern.h>
96#endif
97
98#if NBPF > 0
99#include <sys/time.h>
100#include <net/bpf.h>
101#endif
102
103#include <net/net_osdep.h>
104#include <net/if_gre.h>
105
106/*
107 * It is not easy to calculate the right value for a GRE MTU.
108 * We leave this task to the admin and use the same default that
109 * other vendors use.
110 */
111#define GREMTU 1476
112
113#define GRENAME "gre"
114
115static MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation");
116
117struct gre_softc_head gre_softc_list;
118int ip_gre_ttl = GRE_TTL;
119
118
120int gre_clone_create __P((struct if_clone *, int));
121void gre_clone_destroy __P((struct ifnet *));
119static int gre_clone_create __P((struct if_clone *, int));
120static void gre_clone_destroy __P((struct ifnet *));
121static int gre_ioctl(struct ifnet *, u_long, caddr_t);
122static int gre_output(struct ifnet *, struct mbuf *, struct sockaddr *,
123 struct rtentry *rt);
122
124
123struct if_clone gre_cloner =
125static struct if_clone gre_cloner =
124 IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy, 0, IF_MAXUNIT);
125
126 IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy, 0, IF_MAXUNIT);
127
126int gre_compute_route(struct gre_softc *sc);
128static int gre_compute_route(struct gre_softc *sc);
127
129
128void greattach __P((void));
130static void greattach __P((void));
129
130#ifdef INET
131extern struct domain inetdomain;
132static const struct protosw in_gre_protosw =
133{ SOCK_RAW, &inetdomain, IPPROTO_GRE, PR_ATOMIC|PR_ADDR,
134 (pr_input_t*)gre_input, (pr_output_t*)rip_output, rip_ctlinput, rip_ctloutput,
135 0,
136 0, 0, 0, 0,
137 &rip_usrreqs
138};
139static const struct protosw in_mobile_protosw =
140{ SOCK_RAW, &inetdomain, IPPROTO_MOBILE, PR_ATOMIC|PR_ADDR,
141 (pr_input_t*)gre_mobile_input, (pr_output_t*)rip_output, rip_ctlinput, rip_ctloutput,
142 0,
143 0, 0, 0, 0,
144 &rip_usrreqs
145};
146#endif
147
148SYSCTL_DECL(_net_link);
149SYSCTL_NODE(_net_link, IFT_OTHER, gre, CTLFLAG_RW, 0,
150 "Generic Routing Encapsulation");
151#ifndef MAX_GRE_NEST
152/*
153 * This macro controls the default upper limitation on nesting of gre tunnels.
154 * Since, setting a large value to this macro with a careless configuration
155 * may introduce system crash, we don't allow any nestings by default.
156 * If you need to configure nested gre tunnels, you can define this macro
157 * in your kernel configuration file. However, if you do so, please be
158 * careful to configure the tunnels so that it won't make a loop.
159 */
160#define MAX_GRE_NEST 1
161#endif
162static int max_gre_nesting = MAX_GRE_NEST;
163SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW,
164 &max_gre_nesting, 0, "Max nested tunnels");
165
166/* ARGSUSED */
131
132#ifdef INET
133extern struct domain inetdomain;
134static const struct protosw in_gre_protosw =
135{ SOCK_RAW, &inetdomain, IPPROTO_GRE, PR_ATOMIC|PR_ADDR,
136 (pr_input_t*)gre_input, (pr_output_t*)rip_output, rip_ctlinput, rip_ctloutput,
137 0,
138 0, 0, 0, 0,
139 &rip_usrreqs
140};
141static const struct protosw in_mobile_protosw =
142{ SOCK_RAW, &inetdomain, IPPROTO_MOBILE, PR_ATOMIC|PR_ADDR,
143 (pr_input_t*)gre_mobile_input, (pr_output_t*)rip_output, rip_ctlinput, rip_ctloutput,
144 0,
145 0, 0, 0, 0,
146 &rip_usrreqs
147};
148#endif
149
150SYSCTL_DECL(_net_link);
151SYSCTL_NODE(_net_link, IFT_OTHER, gre, CTLFLAG_RW, 0,
152 "Generic Routing Encapsulation");
153#ifndef MAX_GRE_NEST
154/*
155 * This macro controls the default upper limitation on nesting of gre tunnels.
156 * Since, setting a large value to this macro with a careless configuration
157 * may introduce system crash, we don't allow any nestings by default.
158 * If you need to configure nested gre tunnels, you can define this macro
159 * in your kernel configuration file. However, if you do so, please be
160 * careful to configure the tunnels so that it won't make a loop.
161 */
162#define MAX_GRE_NEST 1
163#endif
164static int max_gre_nesting = MAX_GRE_NEST;
165SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW,
166 &max_gre_nesting, 0, "Max nested tunnels");
167
168/* ARGSUSED */
167void
169static void
168greattach(void)
169{
170
171 LIST_INIT(&gre_softc_list);
172 if_clone_attach(&gre_cloner);
173}
174
170greattach(void)
171{
172
173 LIST_INIT(&gre_softc_list);
174 if_clone_attach(&gre_cloner);
175}
176
175int
177static int
176gre_clone_create(ifc, unit)
177 struct if_clone *ifc;
178 int unit;
179{
180 struct gre_softc *sc;
181
182 sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK);
183 memset(sc, 0, sizeof(struct gre_softc));
184
185 sc->sc_if.if_name = GRENAME;
186 sc->sc_if.if_softc = sc;
187 sc->sc_if.if_unit = unit;
188 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
189 sc->sc_if.if_type = IFT_OTHER;
190 sc->sc_if.if_addrlen = 0;
191 sc->sc_if.if_hdrlen = 24; /* IP + GRE */
192 sc->sc_if.if_mtu = GREMTU;
193 sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
194 sc->sc_if.if_output = gre_output;
195 sc->sc_if.if_ioctl = gre_ioctl;
196 sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
197 sc->g_proto = IPPROTO_GRE;
198 sc->sc_if.if_flags |= IFF_LINK0;
199 sc->encap = NULL;
200 sc->called = 0;
201 if_attach(&sc->sc_if);
202#if NBPF
203 bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
204#endif
205 LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
206 return (0);
207}
208
178gre_clone_create(ifc, unit)
179 struct if_clone *ifc;
180 int unit;
181{
182 struct gre_softc *sc;
183
184 sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK);
185 memset(sc, 0, sizeof(struct gre_softc));
186
187 sc->sc_if.if_name = GRENAME;
188 sc->sc_if.if_softc = sc;
189 sc->sc_if.if_unit = unit;
190 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
191 sc->sc_if.if_type = IFT_OTHER;
192 sc->sc_if.if_addrlen = 0;
193 sc->sc_if.if_hdrlen = 24; /* IP + GRE */
194 sc->sc_if.if_mtu = GREMTU;
195 sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
196 sc->sc_if.if_output = gre_output;
197 sc->sc_if.if_ioctl = gre_ioctl;
198 sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
199 sc->g_proto = IPPROTO_GRE;
200 sc->sc_if.if_flags |= IFF_LINK0;
201 sc->encap = NULL;
202 sc->called = 0;
203 if_attach(&sc->sc_if);
204#if NBPF
205 bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
206#endif
207 LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
208 return (0);
209}
210
209void
211static void
210gre_clone_destroy(ifp)
211 struct ifnet *ifp;
212{
213 struct gre_softc *sc = ifp->if_softc;
214
215#ifdef INET
216 if (sc->encap != NULL)
217 encap_detach(sc->encap);
218#endif
219 LIST_REMOVE(sc, sc_list);
220#if NBPF
221 bpfdetach(ifp);
222#endif
223 if_detach(ifp);
224 free(sc, M_GRE);
225}
226
227/*
228 * The output routine. Takes a packet and encapsulates it in the protocol
229 * given by sc->g_proto. See also RFC 1701 and RFC 2004
230 */
212gre_clone_destroy(ifp)
213 struct ifnet *ifp;
214{
215 struct gre_softc *sc = ifp->if_softc;
216
217#ifdef INET
218 if (sc->encap != NULL)
219 encap_detach(sc->encap);
220#endif
221 LIST_REMOVE(sc, sc_list);
222#if NBPF
223 bpfdetach(ifp);
224#endif
225 if_detach(ifp);
226 free(sc, M_GRE);
227}
228
229/*
230 * The output routine. Takes a packet and encapsulates it in the protocol
231 * given by sc->g_proto. See also RFC 1701 and RFC 2004
232 */
231int
233static int
232gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
233 struct rtentry *rt)
234{
235 int error = 0;
236 struct gre_softc *sc = ifp->if_softc;
237 struct greip *gh;
238 struct ip *ip;
239 u_char osrc;
240 u_short etype = 0;
241 struct mobile_h mob_h;
242
243 /*
244 * gre may cause infinite recursion calls when misconfigured.
245 * We'll prevent this by introducing upper limit.
246 */
247 if (++(sc->called) > max_gre_nesting) {
248 printf("%s: gre_output: recursively called too many "
249 "times(%d)\n", if_name(&sc->sc_if), sc->called);
250 m_freem(m);
251 error = EIO; /* is there better errno? */
252 goto end;
253 }
254
255 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 0 ||
256 sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
257 m_freem(m);
258 error = ENETDOWN;
259 goto end;
260 }
261
262 gh = NULL;
263 ip = NULL;
264 osrc = 0;
265
266#if NBPF
267 if (ifp->if_bpf) {
268 /* see comment of other if_foo.c files */
269 struct mbuf m0;
270 u_int32_t af = dst->sa_family;
271
272 m0.m_next = m;
273 m0.m_len = 4;
274 m0.m_data = (char *)&af;
275
276 bpf_mtap(ifp, &m0);
277 }
278#endif
279
280 m->m_flags &= ~(M_BCAST|M_MCAST);
281
282 if (sc->g_proto == IPPROTO_MOBILE) {
283 if (dst->sa_family == AF_INET) {
284 struct mbuf *m0;
285 int msiz;
286
287 ip = mtod(m, struct ip *);
288
289 /*
290 * RFC2004 specifies that fragmented diagrams shouldn't
291 * be encapsulated.
292 */
293 if ((ip->ip_off & IP_MF) != 0) {
294 _IF_DROP(&ifp->if_snd);
295 m_freem(m);
296 error = EINVAL; /* is there better errno? */
297 goto end;
298 }
299 memset(&mob_h, 0, MOB_H_SIZ_L);
300 mob_h.proto = (ip->ip_p) << 8;
301 mob_h.odst = ip->ip_dst.s_addr;
302 ip->ip_dst.s_addr = sc->g_dst.s_addr;
303
304 /*
305 * If the packet comes from our host, we only change
306 * the destination address in the IP header.
307 * Else we also need to save and change the source
308 */
309 if (in_hosteq(ip->ip_src, sc->g_src)) {
310 msiz = MOB_H_SIZ_S;
311 } else {
312 mob_h.proto |= MOB_H_SBIT;
313 mob_h.osrc = ip->ip_src.s_addr;
314 ip->ip_src.s_addr = sc->g_src.s_addr;
315 msiz = MOB_H_SIZ_L;
316 }
317 mob_h.proto = htons(mob_h.proto);
318 mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
319
320 if ((m->m_data - msiz) < m->m_pktdat) {
321 /* need new mbuf */
322 MGETHDR(m0, M_DONTWAIT, MT_HEADER);
323 if (m0 == NULL) {
324 _IF_DROP(&ifp->if_snd);
325 m_freem(m);
326 error = ENOBUFS;
327 goto end;
328 }
329 m0->m_next = m;
330 m->m_data += sizeof(struct ip);
331 m->m_len -= sizeof(struct ip);
332 m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
333 m0->m_len = msiz + sizeof(struct ip);
334 m0->m_data += max_linkhdr;
335 memcpy(mtod(m0, caddr_t), (caddr_t)ip,
336 sizeof(struct ip));
337 m = m0;
338 } else { /* we have some space left in the old one */
339 m->m_data -= msiz;
340 m->m_len += msiz;
341 m->m_pkthdr.len += msiz;
342 bcopy(ip, mtod(m, caddr_t),
343 sizeof(struct ip));
344 }
345 ip = mtod(m, struct ip *);
346 memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
347 ip->ip_len = ntohs(ip->ip_len) + msiz;
348 } else { /* AF_INET */
349 _IF_DROP(&ifp->if_snd);
350 m_freem(m);
351 error = EINVAL;
352 goto end;
353 }
354 } else if (sc->g_proto == IPPROTO_GRE) {
355 switch (dst->sa_family) {
356 case AF_INET:
357 ip = mtod(m, struct ip *);
358 etype = ETHERTYPE_IP;
359 break;
360#ifdef NETATALK
361 case AF_APPLETALK:
362 etype = ETHERTYPE_ATALK;
363 break;
364#endif
365#ifdef NS
366 case AF_NS:
367 etype = ETHERTYPE_NS;
368 break;
369#endif
370 default:
371 _IF_DROP(&ifp->if_snd);
372 m_freem(m);
373 error = EAFNOSUPPORT;
374 goto end;
375 }
376 M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
377 } else {
378 _IF_DROP(&ifp->if_snd);
379 m_freem(m);
380 error = EINVAL;
381 goto end;
382 }
383
384 if (m == NULL) { /* impossible */
385 _IF_DROP(&ifp->if_snd);
386 error = ENOBUFS;
387 goto end;
388 }
389
390 gh = mtod(m, struct greip *);
391 if (sc->g_proto == IPPROTO_GRE) {
392 /* we don't have any GRE flags for now */
393
394 memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
395 gh->gi_ptype = htons(etype);
396 }
397
398 gh->gi_pr = sc->g_proto;
399 if (sc->g_proto != IPPROTO_MOBILE) {
400 gh->gi_src = sc->g_src;
401 gh->gi_dst = sc->g_dst;
402 ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
234gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
235 struct rtentry *rt)
236{
237 int error = 0;
238 struct gre_softc *sc = ifp->if_softc;
239 struct greip *gh;
240 struct ip *ip;
241 u_char osrc;
242 u_short etype = 0;
243 struct mobile_h mob_h;
244
245 /*
246 * gre may cause infinite recursion calls when misconfigured.
247 * We'll prevent this by introducing upper limit.
248 */
249 if (++(sc->called) > max_gre_nesting) {
250 printf("%s: gre_output: recursively called too many "
251 "times(%d)\n", if_name(&sc->sc_if), sc->called);
252 m_freem(m);
253 error = EIO; /* is there better errno? */
254 goto end;
255 }
256
257 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 0 ||
258 sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
259 m_freem(m);
260 error = ENETDOWN;
261 goto end;
262 }
263
264 gh = NULL;
265 ip = NULL;
266 osrc = 0;
267
268#if NBPF
269 if (ifp->if_bpf) {
270 /* see comment of other if_foo.c files */
271 struct mbuf m0;
272 u_int32_t af = dst->sa_family;
273
274 m0.m_next = m;
275 m0.m_len = 4;
276 m0.m_data = (char *)&af;
277
278 bpf_mtap(ifp, &m0);
279 }
280#endif
281
282 m->m_flags &= ~(M_BCAST|M_MCAST);
283
284 if (sc->g_proto == IPPROTO_MOBILE) {
285 if (dst->sa_family == AF_INET) {
286 struct mbuf *m0;
287 int msiz;
288
289 ip = mtod(m, struct ip *);
290
291 /*
292 * RFC2004 specifies that fragmented diagrams shouldn't
293 * be encapsulated.
294 */
295 if ((ip->ip_off & IP_MF) != 0) {
296 _IF_DROP(&ifp->if_snd);
297 m_freem(m);
298 error = EINVAL; /* is there better errno? */
299 goto end;
300 }
301 memset(&mob_h, 0, MOB_H_SIZ_L);
302 mob_h.proto = (ip->ip_p) << 8;
303 mob_h.odst = ip->ip_dst.s_addr;
304 ip->ip_dst.s_addr = sc->g_dst.s_addr;
305
306 /*
307 * If the packet comes from our host, we only change
308 * the destination address in the IP header.
309 * Else we also need to save and change the source
310 */
311 if (in_hosteq(ip->ip_src, sc->g_src)) {
312 msiz = MOB_H_SIZ_S;
313 } else {
314 mob_h.proto |= MOB_H_SBIT;
315 mob_h.osrc = ip->ip_src.s_addr;
316 ip->ip_src.s_addr = sc->g_src.s_addr;
317 msiz = MOB_H_SIZ_L;
318 }
319 mob_h.proto = htons(mob_h.proto);
320 mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
321
322 if ((m->m_data - msiz) < m->m_pktdat) {
323 /* need new mbuf */
324 MGETHDR(m0, M_DONTWAIT, MT_HEADER);
325 if (m0 == NULL) {
326 _IF_DROP(&ifp->if_snd);
327 m_freem(m);
328 error = ENOBUFS;
329 goto end;
330 }
331 m0->m_next = m;
332 m->m_data += sizeof(struct ip);
333 m->m_len -= sizeof(struct ip);
334 m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
335 m0->m_len = msiz + sizeof(struct ip);
336 m0->m_data += max_linkhdr;
337 memcpy(mtod(m0, caddr_t), (caddr_t)ip,
338 sizeof(struct ip));
339 m = m0;
340 } else { /* we have some space left in the old one */
341 m->m_data -= msiz;
342 m->m_len += msiz;
343 m->m_pkthdr.len += msiz;
344 bcopy(ip, mtod(m, caddr_t),
345 sizeof(struct ip));
346 }
347 ip = mtod(m, struct ip *);
348 memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
349 ip->ip_len = ntohs(ip->ip_len) + msiz;
350 } else { /* AF_INET */
351 _IF_DROP(&ifp->if_snd);
352 m_freem(m);
353 error = EINVAL;
354 goto end;
355 }
356 } else if (sc->g_proto == IPPROTO_GRE) {
357 switch (dst->sa_family) {
358 case AF_INET:
359 ip = mtod(m, struct ip *);
360 etype = ETHERTYPE_IP;
361 break;
362#ifdef NETATALK
363 case AF_APPLETALK:
364 etype = ETHERTYPE_ATALK;
365 break;
366#endif
367#ifdef NS
368 case AF_NS:
369 etype = ETHERTYPE_NS;
370 break;
371#endif
372 default:
373 _IF_DROP(&ifp->if_snd);
374 m_freem(m);
375 error = EAFNOSUPPORT;
376 goto end;
377 }
378 M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
379 } else {
380 _IF_DROP(&ifp->if_snd);
381 m_freem(m);
382 error = EINVAL;
383 goto end;
384 }
385
386 if (m == NULL) { /* impossible */
387 _IF_DROP(&ifp->if_snd);
388 error = ENOBUFS;
389 goto end;
390 }
391
392 gh = mtod(m, struct greip *);
393 if (sc->g_proto == IPPROTO_GRE) {
394 /* we don't have any GRE flags for now */
395
396 memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
397 gh->gi_ptype = htons(etype);
398 }
399
400 gh->gi_pr = sc->g_proto;
401 if (sc->g_proto != IPPROTO_MOBILE) {
402 gh->gi_src = sc->g_src;
403 gh->gi_dst = sc->g_dst;
404 ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
403 ((struct ip*)gh)->ip_ttl = ip_gre_ttl;
405 ((struct ip*)gh)->ip_ttl = GRE_TTL;
404 ((struct ip*)gh)->ip_tos = ip->ip_tos;
405 ((struct ip*)gh)->ip_id = ip->ip_id;
406 gh->gi_len = m->m_pkthdr.len;
407 }
408
409 ifp->if_opackets++;
410 ifp->if_obytes += m->m_pkthdr.len;
411 /* send it off */
412 error = ip_output(m, NULL, &sc->route, 0, NULL);
413 end:
414 sc->called = 0;
415 if (error)
416 ifp->if_oerrors++;
417 return (error);
418}
419
406 ((struct ip*)gh)->ip_tos = ip->ip_tos;
407 ((struct ip*)gh)->ip_id = ip->ip_id;
408 gh->gi_len = m->m_pkthdr.len;
409 }
410
411 ifp->if_opackets++;
412 ifp->if_obytes += m->m_pkthdr.len;
413 /* send it off */
414 error = ip_output(m, NULL, &sc->route, 0, NULL);
415 end:
416 sc->called = 0;
417 if (error)
418 ifp->if_oerrors++;
419 return (error);
420}
421
420int
422static int
421gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
422{
423 struct ifreq *ifr = (struct ifreq *)data;
424 struct if_laddrreq *lifr = (struct if_laddrreq *)data;
425 struct in_aliasreq *aifr = (struct in_aliasreq *)data;
426 struct gre_softc *sc = ifp->if_softc;
427 int s;
428 struct sockaddr_in si;
429 struct sockaddr *sa = NULL;
430 int error;
431 struct sockaddr_in sp, sm, dp, dm;
432
433 error = 0;
434
435 s = splnet();
436 switch (cmd) {
437 case SIOCSIFADDR:
438 ifp->if_flags |= IFF_UP;
439 break;
440 case SIOCSIFDSTADDR:
441 break;
442 case SIOCSIFFLAGS:
443 if ((error = suser(curthread)) != 0)
444 break;
445 if ((ifr->ifr_flags & IFF_LINK0) != 0)
446 sc->g_proto = IPPROTO_GRE;
447 else
448 sc->g_proto = IPPROTO_MOBILE;
449 goto recompute;
450 case SIOCSIFMTU:
451 if ((error = suser(curthread)) != 0)
452 break;
453 if (ifr->ifr_mtu < 576) {
454 error = EINVAL;
455 break;
456 }
457 ifp->if_mtu = ifr->ifr_mtu;
458 break;
459 case SIOCGIFMTU:
460 ifr->ifr_mtu = sc->sc_if.if_mtu;
461 break;
462 case SIOCADDMULTI:
463 case SIOCDELMULTI:
464 if ((error = suser(curthread)) != 0)
465 break;
466 if (ifr == 0) {
467 error = EAFNOSUPPORT;
468 break;
469 }
470 switch (ifr->ifr_addr.sa_family) {
471#ifdef INET
472 case AF_INET:
473 break;
474#endif
475 default:
476 error = EAFNOSUPPORT;
477 break;
478 }
479 break;
480 case GRESPROTO:
481 if ((error = suser(curthread)) != 0)
482 break;
483 sc->g_proto = ifr->ifr_flags;
484 switch (sc->g_proto) {
485 case IPPROTO_GRE:
486 ifp->if_flags |= IFF_LINK0;
487 break;
488 case IPPROTO_MOBILE:
489 ifp->if_flags &= ~IFF_LINK0;
490 break;
491 default:
492 error = EPROTONOSUPPORT;
493 break;
494 }
495 goto recompute;
496 case GREGPROTO:
497 ifr->ifr_flags = sc->g_proto;
498 break;
499 case GRESADDRS:
500 case GRESADDRD:
501 if ((error = suser(curthread)) != 0)
502 break;
503 /*
504 * set tunnel endpoints, compute a less specific route
505 * to the remote end and mark if as up
506 */
507 sa = &ifr->ifr_addr;
508 if (cmd == GRESADDRS)
509 sc->g_src = (satosin(sa))->sin_addr;
510 if (cmd == GRESADDRD)
511 sc->g_dst = (satosin(sa))->sin_addr;
512 recompute:
513#ifdef INET
514 if (sc->encap != NULL) {
515 encap_detach(sc->encap);
516 sc->encap = NULL;
517 }
518#endif
519 if ((sc->g_src.s_addr != INADDR_ANY) &&
520 (sc->g_dst.s_addr != INADDR_ANY)) {
521 bzero(&sp, sizeof(sp));
522 bzero(&sm, sizeof(sm));
523 bzero(&dp, sizeof(dp));
524 bzero(&dm, sizeof(dm));
525 sp.sin_len = sm.sin_len = dp.sin_len = dm.sin_len =
526 sizeof(struct sockaddr_in);
527 sp.sin_family = sm.sin_family = dp.sin_family =
528 dm.sin_family = AF_INET;
529 sp.sin_addr = sc->g_src;
530 dp.sin_addr = sc->g_dst;
531 sm.sin_addr.s_addr = dm.sin_addr.s_addr =
532 INADDR_BROADCAST;
533#ifdef INET
534 sc->encap = encap_attach(AF_INET, sc->g_proto,
535 sintosa(&sp), sintosa(&sm), sintosa(&dp),
536 sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ?
537 &in_gre_protosw : &in_mobile_protosw, sc);
538 if (sc->encap == NULL)
539 printf("%s: unable to attach encap\n",
540 if_name(&sc->sc_if));
541#endif
542 if (sc->route.ro_rt != 0) /* free old route */
543 RTFREE(sc->route.ro_rt);
544 if (gre_compute_route(sc) == 0)
545 ifp->if_flags |= IFF_RUNNING;
546 else
547 ifp->if_flags &= ~IFF_RUNNING;
548 }
549 break;
550 case GREGADDRS:
551 memset(&si, 0, sizeof(si));
552 si.sin_family = AF_INET;
553 si.sin_len = sizeof(struct sockaddr_in);
554 si.sin_addr.s_addr = sc->g_src.s_addr;
555 sa = sintosa(&si);
556 ifr->ifr_addr = *sa;
557 break;
558 case GREGADDRD:
559 memset(&si, 0, sizeof(si));
560 si.sin_family = AF_INET;
561 si.sin_len = sizeof(struct sockaddr_in);
562 si.sin_addr.s_addr = sc->g_dst.s_addr;
563 sa = sintosa(&si);
564 ifr->ifr_addr = *sa;
565 break;
566 case SIOCSIFPHYADDR:
567 if ((error = suser(curthread)) != 0)
568 break;
569 if (aifr->ifra_addr.sin_family != AF_INET ||
570 aifr->ifra_dstaddr.sin_family != AF_INET) {
571 error = EAFNOSUPPORT;
572 break;
573 }
574 if (aifr->ifra_addr.sin_len != sizeof(si) ||
575 aifr->ifra_dstaddr.sin_len != sizeof(si)) {
576 error = EINVAL;
577 break;
578 }
579 sc->g_src = aifr->ifra_addr.sin_addr;
580 sc->g_dst = aifr->ifra_dstaddr.sin_addr;
581 goto recompute;
582 case SIOCSLIFPHYADDR:
583 if ((error = suser(curthread)) != 0)
584 break;
585 if (lifr->addr.ss_family != AF_INET ||
586 lifr->dstaddr.ss_family != AF_INET) {
587 error = EAFNOSUPPORT;
588 break;
589 }
590 if (lifr->addr.ss_len != sizeof(si) ||
591 lifr->dstaddr.ss_len != sizeof(si)) {
592 error = EINVAL;
593 break;
594 }
595 sc->g_src = (satosin((struct sockadrr *)&lifr->addr))->sin_addr;
596 sc->g_dst =
597 (satosin((struct sockadrr *)&lifr->dstaddr))->sin_addr;
598 goto recompute;
599 case SIOCDIFPHYADDR:
600 if ((error = suser(curthread)) != 0)
601 break;
602 sc->g_src.s_addr = INADDR_ANY;
603 sc->g_dst.s_addr = INADDR_ANY;
604 goto recompute;
605 case SIOCGLIFPHYADDR:
606 if (sc->g_src.s_addr == INADDR_ANY ||
607 sc->g_dst.s_addr == INADDR_ANY) {
608 error = EADDRNOTAVAIL;
609 break;
610 }
611 memset(&si, 0, sizeof(si));
612 si.sin_family = AF_INET;
613 si.sin_len = sizeof(struct sockaddr_in);
614 si.sin_addr.s_addr = sc->g_src.s_addr;
615 memcpy(&lifr->addr, &si, sizeof(si));
616 si.sin_addr.s_addr = sc->g_dst.s_addr;
617 memcpy(&lifr->dstaddr, &si, sizeof(si));
618 break;
619 case SIOCGIFPSRCADDR:
620 if (sc->g_src.s_addr == INADDR_ANY) {
621 error = EADDRNOTAVAIL;
622 break;
623 }
624 memset(&si, 0, sizeof(si));
625 si.sin_family = AF_INET;
626 si.sin_len = sizeof(struct sockaddr_in);
627 si.sin_addr.s_addr = sc->g_src.s_addr;
628 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
629 break;
630 case SIOCGIFPDSTADDR:
631 if (sc->g_dst.s_addr == INADDR_ANY) {
632 error = EADDRNOTAVAIL;
633 break;
634 }
635 memset(&si, 0, sizeof(si));
636 si.sin_family = AF_INET;
637 si.sin_len = sizeof(struct sockaddr_in);
638 si.sin_addr.s_addr = sc->g_dst.s_addr;
639 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
640 break;
641 default:
642 error = EINVAL;
643 break;
644 }
645
646 splx(s);
647 return (error);
648}
649
650/*
651 * computes a route to our destination that is not the one
652 * which would be taken by ip_output(), as this one will loop back to
653 * us. If the interface is p2p as a--->b, then a routing entry exists
654 * If we now send a packet to b (e.g. ping b), this will come down here
655 * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
656 * if_gre.
657 * Goal here is to compute a route to b that is less specific than
658 * a-->b. We know that this one exists as in normal operation we have
659 * at least a default route which matches.
660 */
423gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
424{
425 struct ifreq *ifr = (struct ifreq *)data;
426 struct if_laddrreq *lifr = (struct if_laddrreq *)data;
427 struct in_aliasreq *aifr = (struct in_aliasreq *)data;
428 struct gre_softc *sc = ifp->if_softc;
429 int s;
430 struct sockaddr_in si;
431 struct sockaddr *sa = NULL;
432 int error;
433 struct sockaddr_in sp, sm, dp, dm;
434
435 error = 0;
436
437 s = splnet();
438 switch (cmd) {
439 case SIOCSIFADDR:
440 ifp->if_flags |= IFF_UP;
441 break;
442 case SIOCSIFDSTADDR:
443 break;
444 case SIOCSIFFLAGS:
445 if ((error = suser(curthread)) != 0)
446 break;
447 if ((ifr->ifr_flags & IFF_LINK0) != 0)
448 sc->g_proto = IPPROTO_GRE;
449 else
450 sc->g_proto = IPPROTO_MOBILE;
451 goto recompute;
452 case SIOCSIFMTU:
453 if ((error = suser(curthread)) != 0)
454 break;
455 if (ifr->ifr_mtu < 576) {
456 error = EINVAL;
457 break;
458 }
459 ifp->if_mtu = ifr->ifr_mtu;
460 break;
461 case SIOCGIFMTU:
462 ifr->ifr_mtu = sc->sc_if.if_mtu;
463 break;
464 case SIOCADDMULTI:
465 case SIOCDELMULTI:
466 if ((error = suser(curthread)) != 0)
467 break;
468 if (ifr == 0) {
469 error = EAFNOSUPPORT;
470 break;
471 }
472 switch (ifr->ifr_addr.sa_family) {
473#ifdef INET
474 case AF_INET:
475 break;
476#endif
477 default:
478 error = EAFNOSUPPORT;
479 break;
480 }
481 break;
482 case GRESPROTO:
483 if ((error = suser(curthread)) != 0)
484 break;
485 sc->g_proto = ifr->ifr_flags;
486 switch (sc->g_proto) {
487 case IPPROTO_GRE:
488 ifp->if_flags |= IFF_LINK0;
489 break;
490 case IPPROTO_MOBILE:
491 ifp->if_flags &= ~IFF_LINK0;
492 break;
493 default:
494 error = EPROTONOSUPPORT;
495 break;
496 }
497 goto recompute;
498 case GREGPROTO:
499 ifr->ifr_flags = sc->g_proto;
500 break;
501 case GRESADDRS:
502 case GRESADDRD:
503 if ((error = suser(curthread)) != 0)
504 break;
505 /*
506 * set tunnel endpoints, compute a less specific route
507 * to the remote end and mark if as up
508 */
509 sa = &ifr->ifr_addr;
510 if (cmd == GRESADDRS)
511 sc->g_src = (satosin(sa))->sin_addr;
512 if (cmd == GRESADDRD)
513 sc->g_dst = (satosin(sa))->sin_addr;
514 recompute:
515#ifdef INET
516 if (sc->encap != NULL) {
517 encap_detach(sc->encap);
518 sc->encap = NULL;
519 }
520#endif
521 if ((sc->g_src.s_addr != INADDR_ANY) &&
522 (sc->g_dst.s_addr != INADDR_ANY)) {
523 bzero(&sp, sizeof(sp));
524 bzero(&sm, sizeof(sm));
525 bzero(&dp, sizeof(dp));
526 bzero(&dm, sizeof(dm));
527 sp.sin_len = sm.sin_len = dp.sin_len = dm.sin_len =
528 sizeof(struct sockaddr_in);
529 sp.sin_family = sm.sin_family = dp.sin_family =
530 dm.sin_family = AF_INET;
531 sp.sin_addr = sc->g_src;
532 dp.sin_addr = sc->g_dst;
533 sm.sin_addr.s_addr = dm.sin_addr.s_addr =
534 INADDR_BROADCAST;
535#ifdef INET
536 sc->encap = encap_attach(AF_INET, sc->g_proto,
537 sintosa(&sp), sintosa(&sm), sintosa(&dp),
538 sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ?
539 &in_gre_protosw : &in_mobile_protosw, sc);
540 if (sc->encap == NULL)
541 printf("%s: unable to attach encap\n",
542 if_name(&sc->sc_if));
543#endif
544 if (sc->route.ro_rt != 0) /* free old route */
545 RTFREE(sc->route.ro_rt);
546 if (gre_compute_route(sc) == 0)
547 ifp->if_flags |= IFF_RUNNING;
548 else
549 ifp->if_flags &= ~IFF_RUNNING;
550 }
551 break;
552 case GREGADDRS:
553 memset(&si, 0, sizeof(si));
554 si.sin_family = AF_INET;
555 si.sin_len = sizeof(struct sockaddr_in);
556 si.sin_addr.s_addr = sc->g_src.s_addr;
557 sa = sintosa(&si);
558 ifr->ifr_addr = *sa;
559 break;
560 case GREGADDRD:
561 memset(&si, 0, sizeof(si));
562 si.sin_family = AF_INET;
563 si.sin_len = sizeof(struct sockaddr_in);
564 si.sin_addr.s_addr = sc->g_dst.s_addr;
565 sa = sintosa(&si);
566 ifr->ifr_addr = *sa;
567 break;
568 case SIOCSIFPHYADDR:
569 if ((error = suser(curthread)) != 0)
570 break;
571 if (aifr->ifra_addr.sin_family != AF_INET ||
572 aifr->ifra_dstaddr.sin_family != AF_INET) {
573 error = EAFNOSUPPORT;
574 break;
575 }
576 if (aifr->ifra_addr.sin_len != sizeof(si) ||
577 aifr->ifra_dstaddr.sin_len != sizeof(si)) {
578 error = EINVAL;
579 break;
580 }
581 sc->g_src = aifr->ifra_addr.sin_addr;
582 sc->g_dst = aifr->ifra_dstaddr.sin_addr;
583 goto recompute;
584 case SIOCSLIFPHYADDR:
585 if ((error = suser(curthread)) != 0)
586 break;
587 if (lifr->addr.ss_family != AF_INET ||
588 lifr->dstaddr.ss_family != AF_INET) {
589 error = EAFNOSUPPORT;
590 break;
591 }
592 if (lifr->addr.ss_len != sizeof(si) ||
593 lifr->dstaddr.ss_len != sizeof(si)) {
594 error = EINVAL;
595 break;
596 }
597 sc->g_src = (satosin((struct sockadrr *)&lifr->addr))->sin_addr;
598 sc->g_dst =
599 (satosin((struct sockadrr *)&lifr->dstaddr))->sin_addr;
600 goto recompute;
601 case SIOCDIFPHYADDR:
602 if ((error = suser(curthread)) != 0)
603 break;
604 sc->g_src.s_addr = INADDR_ANY;
605 sc->g_dst.s_addr = INADDR_ANY;
606 goto recompute;
607 case SIOCGLIFPHYADDR:
608 if (sc->g_src.s_addr == INADDR_ANY ||
609 sc->g_dst.s_addr == INADDR_ANY) {
610 error = EADDRNOTAVAIL;
611 break;
612 }
613 memset(&si, 0, sizeof(si));
614 si.sin_family = AF_INET;
615 si.sin_len = sizeof(struct sockaddr_in);
616 si.sin_addr.s_addr = sc->g_src.s_addr;
617 memcpy(&lifr->addr, &si, sizeof(si));
618 si.sin_addr.s_addr = sc->g_dst.s_addr;
619 memcpy(&lifr->dstaddr, &si, sizeof(si));
620 break;
621 case SIOCGIFPSRCADDR:
622 if (sc->g_src.s_addr == INADDR_ANY) {
623 error = EADDRNOTAVAIL;
624 break;
625 }
626 memset(&si, 0, sizeof(si));
627 si.sin_family = AF_INET;
628 si.sin_len = sizeof(struct sockaddr_in);
629 si.sin_addr.s_addr = sc->g_src.s_addr;
630 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
631 break;
632 case SIOCGIFPDSTADDR:
633 if (sc->g_dst.s_addr == INADDR_ANY) {
634 error = EADDRNOTAVAIL;
635 break;
636 }
637 memset(&si, 0, sizeof(si));
638 si.sin_family = AF_INET;
639 si.sin_len = sizeof(struct sockaddr_in);
640 si.sin_addr.s_addr = sc->g_dst.s_addr;
641 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
642 break;
643 default:
644 error = EINVAL;
645 break;
646 }
647
648 splx(s);
649 return (error);
650}
651
652/*
653 * computes a route to our destination that is not the one
654 * which would be taken by ip_output(), as this one will loop back to
655 * us. If the interface is p2p as a--->b, then a routing entry exists
656 * If we now send a packet to b (e.g. ping b), this will come down here
657 * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
658 * if_gre.
659 * Goal here is to compute a route to b that is less specific than
660 * a-->b. We know that this one exists as in normal operation we have
661 * at least a default route which matches.
662 */
661int
663static int
662gre_compute_route(struct gre_softc *sc)
663{
664 struct route *ro;
665 u_int32_t a, b, c;
666
667 ro = &sc->route;
668
669 memset(ro, 0, sizeof(struct route));
670 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
671 ro->ro_dst.sa_family = AF_INET;
672 ro->ro_dst.sa_len = sizeof(ro->ro_dst);
673
674 /*
675 * toggle last bit, so our interface is not found, but a less
676 * specific route. I'd rather like to specify a shorter mask,
677 * but this is not possible. Should work though. XXX
678 * there is a simpler way ...
679 */
680 if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
681 a = ntohl(sc->g_dst.s_addr);
682 b = a & 0x01;
683 c = a & 0xfffffffe;
684 b = b ^ 0x01;
685 a = b | c;
686 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
687 = htonl(a);
688 }
689
690#ifdef DIAGNOSTIC
691 printf("%s: searching a route to %s", if_name(&sc->sc_if),
692 inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr));
693#endif
694
695 rtalloc(ro);
696
697 /*
698 * check if this returned a route at all and this route is no
699 * recursion to ourself
700 */
701 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) {
702#ifdef DIAGNOSTIC
703 if (ro->ro_rt == NULL)
704 printf(" - no route found!\n");
705 else
706 printf(" - route loops back to ourself!\n");
707#endif
708 return EADDRNOTAVAIL;
709 }
710
711 /*
712 * now change it back - else ip_output will just drop
713 * the route and search one to this interface ...
714 */
715 if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
716 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
717
718#ifdef DIAGNOSTIC
719 printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp),
720 inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr));
721 printf("\n");
722#endif
723
724 return 0;
725}
726
727/*
728 * do a checksum of a buffer - much like in_cksum, which operates on
729 * mbufs.
730 */
731u_short
732gre_in_cksum(u_short *p, u_int len)
733{
734 u_int sum = 0;
735 int nwords = len >> 1;
736
737 while (nwords-- != 0)
738 sum += *p++;
739
740 if (len & 1) {
741 union {
742 u_short w;
743 u_char c[2];
744 } u;
745 u.c[0] = *(u_char *)p;
746 u.c[1] = 0;
747 sum += u.w;
748 }
749
750 /* end-around-carry */
751 sum = (sum >> 16) + (sum & 0xffff);
752 sum += (sum >> 16);
753 return (~sum);
754}
755
756static int
757gremodevent(module_t mod, int type, void *data)
758{
759
760 switch (type) {
761 case MOD_LOAD:
762 greattach();
763 break;
764 case MOD_UNLOAD:
765 if_clone_detach(&gre_cloner);
766
767 while (!LIST_EMPTY(&gre_softc_list))
768 gre_clone_destroy(&LIST_FIRST(&gre_softc_list)->sc_if);
769 break;
770 }
771 return 0;
772}
773
774static moduledata_t gre_mod = {
775 "if_gre",
776 gremodevent,
777 0
778};
779
780DECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
781MODULE_VERSION(if_gre, 1);
664gre_compute_route(struct gre_softc *sc)
665{
666 struct route *ro;
667 u_int32_t a, b, c;
668
669 ro = &sc->route;
670
671 memset(ro, 0, sizeof(struct route));
672 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
673 ro->ro_dst.sa_family = AF_INET;
674 ro->ro_dst.sa_len = sizeof(ro->ro_dst);
675
676 /*
677 * toggle last bit, so our interface is not found, but a less
678 * specific route. I'd rather like to specify a shorter mask,
679 * but this is not possible. Should work though. XXX
680 * there is a simpler way ...
681 */
682 if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
683 a = ntohl(sc->g_dst.s_addr);
684 b = a & 0x01;
685 c = a & 0xfffffffe;
686 b = b ^ 0x01;
687 a = b | c;
688 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
689 = htonl(a);
690 }
691
692#ifdef DIAGNOSTIC
693 printf("%s: searching a route to %s", if_name(&sc->sc_if),
694 inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr));
695#endif
696
697 rtalloc(ro);
698
699 /*
700 * check if this returned a route at all and this route is no
701 * recursion to ourself
702 */
703 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) {
704#ifdef DIAGNOSTIC
705 if (ro->ro_rt == NULL)
706 printf(" - no route found!\n");
707 else
708 printf(" - route loops back to ourself!\n");
709#endif
710 return EADDRNOTAVAIL;
711 }
712
713 /*
714 * now change it back - else ip_output will just drop
715 * the route and search one to this interface ...
716 */
717 if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
718 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
719
720#ifdef DIAGNOSTIC
721 printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp),
722 inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr));
723 printf("\n");
724#endif
725
726 return 0;
727}
728
729/*
730 * do a checksum of a buffer - much like in_cksum, which operates on
731 * mbufs.
732 */
733u_short
734gre_in_cksum(u_short *p, u_int len)
735{
736 u_int sum = 0;
737 int nwords = len >> 1;
738
739 while (nwords-- != 0)
740 sum += *p++;
741
742 if (len & 1) {
743 union {
744 u_short w;
745 u_char c[2];
746 } u;
747 u.c[0] = *(u_char *)p;
748 u.c[1] = 0;
749 sum += u.w;
750 }
751
752 /* end-around-carry */
753 sum = (sum >> 16) + (sum & 0xffff);
754 sum += (sum >> 16);
755 return (~sum);
756}
757
758static int
759gremodevent(module_t mod, int type, void *data)
760{
761
762 switch (type) {
763 case MOD_LOAD:
764 greattach();
765 break;
766 case MOD_UNLOAD:
767 if_clone_detach(&gre_cloner);
768
769 while (!LIST_EMPTY(&gre_softc_list))
770 gre_clone_destroy(&LIST_FIRST(&gre_softc_list)->sc_if);
771 break;
772 }
773 return 0;
774}
775
776static moduledata_t gre_mod = {
777 "if_gre",
778 gremodevent,
779 0
780};
781
782DECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
783MODULE_VERSION(if_gre, 1);