if_gre.c revision 1.17.2.1 1 1.17.2.1 nathanw /* $NetBSD: if_gre.c,v 1.17.2.1 2001/03/05 22:49:54 nathanw 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.9 drochner #include "opt_ns.h"
53 1.1 hwr #include "bpfilter.h"
54 1.1 hwr
55 1.1 hwr #include <sys/param.h>
56 1.1 hwr #include <sys/malloc.h>
57 1.1 hwr #include <sys/mbuf.h>
58 1.17.2.1 nathanw #include <sys/lwp.h>
59 1.13 martin #include <sys/proc.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.10 thorpej #include <sys/queue.h>
64 1.1 hwr #if __NetBSD__
65 1.1 hwr #include <sys/systm.h>
66 1.1 hwr #endif
67 1.1 hwr
68 1.1 hwr #include <machine/cpu.h>
69 1.1 hwr
70 1.1 hwr #include <net/ethertypes.h>
71 1.1 hwr #include <net/if.h>
72 1.1 hwr #include <net/if_types.h>
73 1.1 hwr #include <net/netisr.h>
74 1.1 hwr #include <net/route.h>
75 1.1 hwr
76 1.1 hwr #ifdef INET
77 1.1 hwr #include <netinet/in.h>
78 1.1 hwr #include <netinet/in_systm.h>
79 1.1 hwr #include <netinet/in_var.h>
80 1.1 hwr #include <netinet/ip.h>
81 1.1 hwr #include <netinet/ip_var.h>
82 1.1 hwr #else
83 1.4 thorpej #error "Huh? if_gre without inet?"
84 1.1 hwr #endif
85 1.1 hwr
86 1.1 hwr #ifdef NS
87 1.1 hwr #include <netns/ns.h>
88 1.1 hwr #include <netns/ns_if.h>
89 1.1 hwr #endif
90 1.1 hwr
91 1.1 hwr #ifdef NETATALK
92 1.1 hwr #include <netatalk/at.h>
93 1.1 hwr #include <netatalk/at_var.h>
94 1.1 hwr #include <netatalk/at_extern.h>
95 1.1 hwr #endif
96 1.1 hwr
97 1.1 hwr #if NBPFILTER > 0
98 1.1 hwr #include <sys/time.h>
99 1.1 hwr #include <net/bpf.h>
100 1.1 hwr #endif
101 1.1 hwr
102 1.1 hwr #include <net/if_gre.h>
103 1.1 hwr
104 1.1 hwr #define GREMTU 1450 /* XXX this is below the standard MTU of
105 1.1 hwr 1500 Bytes, allowing for headers,
106 1.1 hwr but we should possibly do path mtu discovery
107 1.1 hwr before changing if state to up to find the
108 1.1 hwr correct value */
109 1.3 hwr #define LINK_MASK (IFF_LINK0|IFF_LINK1|IFF_LINK2)
110 1.1 hwr
111 1.11 thorpej struct gre_softc_head gre_softc_list;
112 1.1 hwr
113 1.10 thorpej int gre_clone_create __P((struct if_clone *, int));
114 1.10 thorpej void gre_clone_destroy __P((struct ifnet *));
115 1.10 thorpej
116 1.10 thorpej struct if_clone gre_cloner =
117 1.10 thorpej IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy);
118 1.1 hwr
119 1.1 hwr void gre_compute_route(struct gre_softc *sc);
120 1.1 hwr #ifdef DIAGNOSTIC
121 1.3 hwr void gre_inet_ntoa(struct in_addr in);
122 1.1 hwr #endif
123 1.1 hwr
124 1.10 thorpej void greattach __P((int));
125 1.10 thorpej
126 1.10 thorpej /* ARGSUSED */
127 1.8 explorer void
128 1.10 thorpej greattach(count)
129 1.10 thorpej int count;
130 1.10 thorpej {
131 1.10 thorpej
132 1.10 thorpej LIST_INIT(&gre_softc_list);
133 1.10 thorpej if_clone_attach(&gre_cloner);
134 1.10 thorpej }
135 1.10 thorpej
136 1.10 thorpej int
137 1.10 thorpej gre_clone_create(ifc, unit)
138 1.10 thorpej struct if_clone *ifc;
139 1.10 thorpej int unit;
140 1.1 hwr {
141 1.8 explorer struct gre_softc *sc;
142 1.1 hwr
143 1.10 thorpej sc = malloc(sizeof(struct gre_softc), M_DEVBUF, M_WAITOK);
144 1.10 thorpej memset(sc, 0, sizeof(struct gre_softc));
145 1.10 thorpej
146 1.10 thorpej sprintf(sc->sc_if.if_xname, "%s%d", ifc->ifc_name, unit);
147 1.10 thorpej sc->sc_if.if_softc = sc;
148 1.10 thorpej sc->sc_if.if_type = IFT_OTHER;
149 1.10 thorpej sc->sc_if.if_addrlen = 4;
150 1.10 thorpej sc->sc_if.if_hdrlen = 24; /* IP + GRE */
151 1.15 thorpej sc->sc_if.if_dlt = DLT_NULL;
152 1.10 thorpej sc->sc_if.if_mtu = GREMTU;
153 1.10 thorpej sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
154 1.10 thorpej sc->sc_if.if_output = gre_output;
155 1.10 thorpej sc->sc_if.if_ioctl = gre_ioctl;
156 1.10 thorpej sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
157 1.10 thorpej sc->g_proto = IPPROTO_GRE;
158 1.10 thorpej if_attach(&sc->sc_if);
159 1.16 thorpej if_alloc_sadl(&sc->sc_if);
160 1.1 hwr #if NBPFILTER > 0
161 1.14 thorpej bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
162 1.1 hwr #endif
163 1.10 thorpej LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
164 1.10 thorpej return (0);
165 1.10 thorpej }
166 1.1 hwr
167 1.10 thorpej void
168 1.10 thorpej gre_clone_destroy(ifp)
169 1.10 thorpej struct ifnet *ifp;
170 1.10 thorpej {
171 1.10 thorpej struct gre_softc *sc = ifp->if_softc;
172 1.10 thorpej
173 1.10 thorpej LIST_REMOVE(sc, sc_list);
174 1.10 thorpej #if NBPFILTER > 0
175 1.10 thorpej bpfdetach(ifp);
176 1.10 thorpej #endif
177 1.10 thorpej if_detach(ifp);
178 1.10 thorpej free(sc, M_DEVBUF);
179 1.1 hwr }
180 1.1 hwr
181 1.1 hwr /*
182 1.1 hwr * The output routine. Takes a packet and encapsulates it in the protocol
183 1.6 hwr * given by sc->g_proto. See also RFC 1701 and RFC 2004
184 1.1 hwr */
185 1.1 hwr
186 1.8 explorer #if 0
187 1.1 hwr struct ip ip_h;
188 1.8 explorer #endif
189 1.3 hwr struct mobile_h mob_h;
190 1.1 hwr
191 1.1 hwr int
192 1.8 explorer gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
193 1.8 explorer struct rtentry *rt)
194 1.1 hwr {
195 1.8 explorer int error = 0;
196 1.10 thorpej struct gre_softc *sc = ifp->if_softc;
197 1.1 hwr struct greip *gh;
198 1.1 hwr struct ip *inp;
199 1.8 explorer u_char ttl, osrc;
200 1.8 explorer u_short etype = 0;
201 1.3 hwr
202 1.1 hwr
203 1.8 explorer gh = NULL;
204 1.8 explorer inp = NULL;
205 1.8 explorer osrc = 0;
206 1.1 hwr
207 1.1 hwr #if NBPFILTER >0
208 1.14 thorpej if (ifp->if_bpf) {
209 1.1 hwr /* see comment of other if_foo.c files */
210 1.1 hwr struct mbuf m0;
211 1.17 itojun u_int32_t af = dst->sa_family;
212 1.1 hwr
213 1.8 explorer m0.m_next = m;
214 1.8 explorer m0.m_len = 4;
215 1.1 hwr m0.m_data = (char *)⁡
216 1.1 hwr
217 1.14 thorpej bpf_mtap(ifp->if_bpf, &m0);
218 1.1 hwr }
219 1.1 hwr #endif
220 1.1 hwr
221 1.8 explorer ttl = 255;
222 1.1 hwr
223 1.5 thorpej if (sc->g_proto == IPPROTO_MOBILE) {
224 1.3 hwr if (dst->sa_family == AF_INET) {
225 1.3 hwr struct mbuf *m0;
226 1.3 hwr int msiz;
227 1.3 hwr
228 1.8 explorer inp = mtod(m, struct ip *);
229 1.3 hwr
230 1.8 explorer memset(&mob_h, 0, MOB_H_SIZ_L);
231 1.8 explorer mob_h.proto = (inp->ip_p) << 8;
232 1.8 explorer mob_h.odst = inp->ip_dst.s_addr;
233 1.8 explorer inp->ip_dst.s_addr = sc->g_dst.s_addr;
234 1.3 hwr
235 1.3 hwr /*
236 1.8 explorer * If the packet comes from our host, we only change
237 1.8 explorer * the destination address in the IP header.
238 1.8 explorer * Else we also need to save and change the source
239 1.3 hwr */
240 1.3 hwr if (in_hosteq(inp->ip_src, sc->g_src)) {
241 1.8 explorer msiz = MOB_H_SIZ_S;
242 1.3 hwr } else {
243 1.3 hwr mob_h.proto |= MOB_H_SBIT;
244 1.8 explorer mob_h.osrc = inp->ip_src.s_addr;
245 1.8 explorer inp->ip_src.s_addr = sc->g_src.s_addr;
246 1.8 explorer msiz = MOB_H_SIZ_L;
247 1.3 hwr }
248 1.3 hwr HTONS(mob_h.proto);
249 1.8 explorer mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
250 1.3 hwr
251 1.3 hwr if ((m->m_data - msiz) < m->m_pktdat) {
252 1.3 hwr /* need new mbuf */
253 1.3 hwr MGETHDR(m0, M_DONTWAIT, MT_HEADER);
254 1.8 explorer if (m0 == NULL) {
255 1.3 hwr IF_DROP(&ifp->if_snd);
256 1.3 hwr m_freem(m);
257 1.8 explorer return (ENOBUFS);
258 1.3 hwr }
259 1.8 explorer m0->m_next = m;
260 1.3 hwr m->m_data += sizeof(struct ip);
261 1.3 hwr m->m_len -= sizeof(struct ip);
262 1.8 explorer m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
263 1.3 hwr m0->m_len = msiz + sizeof(struct ip);
264 1.3 hwr m0->m_data += max_linkhdr;
265 1.8 explorer memcpy(mtod(m0, caddr_t), (caddr_t)inp,
266 1.8 explorer sizeof(struct ip));
267 1.8 explorer m = m0;
268 1.8 explorer } else { /* we have some spave left in the old one */
269 1.8 explorer m->m_data -= msiz;
270 1.8 explorer m->m_len += msiz;
271 1.8 explorer m->m_pkthdr.len += msiz;
272 1.8 explorer memmove(mtod(m, caddr_t), inp,
273 1.8 explorer sizeof(struct ip));
274 1.3 hwr }
275 1.8 explorer inp=mtod(m, struct ip *);
276 1.8 explorer memcpy((caddr_t)(inp + 1), &mob_h, (unsigned)msiz);
277 1.3 hwr NTOHS(inp->ip_len);
278 1.8 explorer inp->ip_len += msiz;
279 1.3 hwr } else { /* AF_INET */
280 1.3 hwr IF_DROP(&ifp->if_snd);
281 1.3 hwr m_freem(m);
282 1.8 explorer return (EINVAL);
283 1.3 hwr }
284 1.1 hwr } else if (sc->g_proto == IPPROTO_GRE) {
285 1.1 hwr switch(dst->sa_family) {
286 1.1 hwr case AF_INET:
287 1.8 explorer inp = mtod(m, struct ip *);
288 1.8 explorer ttl = inp->ip_ttl;
289 1.8 explorer etype = ETHERTYPE_IP;
290 1.1 hwr break;
291 1.1 hwr #ifdef NETATALK
292 1.1 hwr case AF_APPLETALK:
293 1.8 explorer etype = ETHERTYPE_ATALK;
294 1.1 hwr break;
295 1.1 hwr #endif
296 1.1 hwr #ifdef NS
297 1.1 hwr case AF_NS:
298 1.8 explorer etype = ETHERTYPE_NS;
299 1.1 hwr break;
300 1.1 hwr #endif
301 1.1 hwr default:
302 1.1 hwr IF_DROP(&ifp->if_snd);
303 1.1 hwr m_freem(m);
304 1.8 explorer return (EAFNOSUPPORT);
305 1.1 hwr }
306 1.8 explorer M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
307 1.1 hwr } else {
308 1.8 explorer error = EINVAL;
309 1.1 hwr IF_DROP(&ifp->if_snd);
310 1.1 hwr m_freem(m);
311 1.8 explorer return (error);
312 1.1 hwr }
313 1.1 hwr
314 1.1 hwr
315 1.1 hwr if (m == NULL) {
316 1.1 hwr IF_DROP(&ifp->if_snd);
317 1.8 explorer return (ENOBUFS);
318 1.1 hwr }
319 1.1 hwr
320 1.8 explorer gh = mtod(m, struct greip *);
321 1.8 explorer if (sc->g_proto == IPPROTO_GRE) {
322 1.1 hwr /* we don't have any GRE flags for now */
323 1.1 hwr
324 1.8 explorer memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
325 1.8 explorer gh->gi_ptype = htons(etype);
326 1.1 hwr }
327 1.1 hwr
328 1.1 hwr gh->gi_pr = sc->g_proto;
329 1.3 hwr if (sc->g_proto != IPPROTO_MOBILE) {
330 1.3 hwr gh->gi_src = sc->g_src;
331 1.3 hwr gh->gi_dst = sc->g_dst;
332 1.3 hwr ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
333 1.8 explorer ((struct ip*)gh)->ip_ttl = ttl;
334 1.8 explorer ((struct ip*)gh)->ip_tos = inp->ip_tos;
335 1.3 hwr gh->gi_len = m->m_pkthdr.len;
336 1.3 hwr }
337 1.1 hwr
338 1.1 hwr ifp->if_opackets++;
339 1.8 explorer ifp->if_obytes += m->m_pkthdr.len;
340 1.1 hwr /* send it off */
341 1.8 explorer error = ip_output(m, NULL, &sc->route, 0, NULL);
342 1.8 explorer if (error)
343 1.1 hwr ifp->if_oerrors++;
344 1.8 explorer return (error);
345 1.1 hwr
346 1.1 hwr }
347 1.1 hwr
348 1.1 hwr int
349 1.8 explorer gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
350 1.1 hwr {
351 1.17.2.1 nathanw struct proc *p = curproc->l_proc; /* XXX */
352 1.8 explorer struct ifaddr *ifa = (struct ifaddr *)data;
353 1.8 explorer struct ifreq *ifr = (struct ifreq *)data;
354 1.8 explorer struct in_ifaddr *ia = (struct in_ifaddr *)data;
355 1.8 explorer struct gre_softc *sc = ifp->if_softc;
356 1.1 hwr int s;
357 1.1 hwr struct sockaddr_in si;
358 1.8 explorer struct sockaddr *sa = NULL;
359 1.1 hwr int error;
360 1.1 hwr
361 1.8 explorer error = 0;
362 1.1 hwr
363 1.1 hwr s = splimp();
364 1.1 hwr switch(cmd) {
365 1.1 hwr case SIOCSIFADDR:
366 1.1 hwr case SIOCSIFDSTADDR:
367 1.13 martin if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
368 1.13 martin break;
369 1.1 hwr /*
370 1.1 hwr * set tunnel endpoints in case that we "only"
371 1.1 hwr * have ip over ip encapsulation. This allows to
372 1.1 hwr * set tunnel endpoints with ifconfig.
373 1.1 hwr */
374 1.1 hwr if (ifa->ifa_addr->sa_family == AF_INET) {
375 1.1 hwr sa = ifa->ifa_addr;
376 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
377 1.1 hwr sc->g_dst = ia->ia_dstaddr.sin_addr;
378 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
379 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
380 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
381 1.1 hwr RTFREE(sc->route.ro_rt);
382 1.1 hwr gre_compute_route(sc);
383 1.1 hwr ifp->if_flags |= IFF_UP;
384 1.1 hwr }
385 1.1 hwr }
386 1.1 hwr break;
387 1.1 hwr case SIOCSIFFLAGS:
388 1.13 martin if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
389 1.13 martin break;
390 1.8 explorer if ((sc->g_dst.s_addr == INADDR_ANY) ||
391 1.8 explorer (sc->g_src.s_addr == INADDR_ANY))
392 1.1 hwr ifp->if_flags &= ~IFF_UP;
393 1.1 hwr
394 1.3 hwr switch(ifr->ifr_flags & LINK_MASK) {
395 1.3 hwr case IFF_LINK0:
396 1.3 hwr sc->g_proto = IPPROTO_GRE;
397 1.3 hwr ifp->if_flags |= IFF_LINK0;
398 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
399 1.3 hwr break;
400 1.3 hwr case IFF_LINK2:
401 1.3 hwr sc->g_proto = IPPROTO_MOBILE;
402 1.3 hwr ifp->if_flags |= IFF_LINK2;
403 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1);
404 1.3 hwr break;
405 1.1 hwr }
406 1.1 hwr break;
407 1.1 hwr case SIOCSIFMTU:
408 1.13 martin if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
409 1.13 martin break;
410 1.1 hwr if (ifr->ifr_mtu > GREMTU || ifr->ifr_mtu < 576) {
411 1.1 hwr error = EINVAL;
412 1.1 hwr break;
413 1.1 hwr }
414 1.1 hwr ifp->if_mtu = ifr->ifr_mtu;
415 1.1 hwr break;
416 1.1 hwr case SIOCGIFMTU:
417 1.1 hwr ifr->ifr_mtu = sc->sc_if.if_mtu;
418 1.1 hwr break;
419 1.1 hwr case SIOCADDMULTI:
420 1.1 hwr case SIOCDELMULTI:
421 1.13 martin if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
422 1.13 martin break;
423 1.8 explorer if (ifr == 0) {
424 1.1 hwr error = EAFNOSUPPORT;
425 1.1 hwr break;
426 1.1 hwr }
427 1.8 explorer switch (ifr->ifr_addr.sa_family) {
428 1.1 hwr #ifdef INET
429 1.1 hwr case AF_INET:
430 1.1 hwr break;
431 1.1 hwr #endif
432 1.1 hwr default:
433 1.1 hwr error = EAFNOSUPPORT;
434 1.1 hwr break;
435 1.1 hwr }
436 1.1 hwr break;
437 1.1 hwr case GRESPROTO:
438 1.13 martin if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
439 1.13 martin break;
440 1.1 hwr sc->g_proto = ifr->ifr_flags;
441 1.1 hwr switch (sc->g_proto) {
442 1.3 hwr case IPPROTO_GRE :
443 1.3 hwr ifp->if_flags |= IFF_LINK0;
444 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
445 1.1 hwr break;
446 1.3 hwr case IPPROTO_MOBILE :
447 1.3 hwr ifp->if_flags |= IFF_LINK2;
448 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
449 1.1 hwr break;
450 1.1 hwr default:
451 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
452 1.1 hwr }
453 1.1 hwr break;
454 1.1 hwr case GREGPROTO:
455 1.1 hwr ifr->ifr_flags = sc->g_proto;
456 1.1 hwr break;
457 1.1 hwr case GRESADDRS:
458 1.1 hwr case GRESADDRD:
459 1.13 martin if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
460 1.13 martin break;
461 1.1 hwr /*
462 1.1 hwr * set tunnel endpoints, compute a less specific route
463 1.1 hwr * to the remote end and mark if as up
464 1.1 hwr */
465 1.1 hwr sa = &ifr->ifr_addr;
466 1.1 hwr if (cmd == GRESADDRS )
467 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
468 1.1 hwr if (cmd == GRESADDRD )
469 1.1 hwr sc->g_dst = (satosin(sa))->sin_addr;
470 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
471 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
472 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
473 1.1 hwr RTFREE(sc->route.ro_rt);
474 1.1 hwr gre_compute_route(sc);
475 1.1 hwr ifp->if_flags |= IFF_UP;
476 1.1 hwr }
477 1.1 hwr break;
478 1.1 hwr case GREGADDRS:
479 1.1 hwr si.sin_addr.s_addr = sc->g_src.s_addr;
480 1.8 explorer sa = sintosa(&si);
481 1.1 hwr ifr->ifr_addr = *sa;
482 1.1 hwr break;
483 1.1 hwr case GREGADDRD:
484 1.1 hwr si.sin_addr.s_addr = sc->g_dst.s_addr;
485 1.8 explorer sa = sintosa(&si);
486 1.1 hwr ifr->ifr_addr = *sa;
487 1.1 hwr break;
488 1.1 hwr default:
489 1.1 hwr error = EINVAL;
490 1.1 hwr }
491 1.1 hwr
492 1.1 hwr splx(s);
493 1.8 explorer return (error);
494 1.1 hwr }
495 1.1 hwr
496 1.1 hwr /*
497 1.1 hwr * computes a route to our destination that is not the one
498 1.1 hwr * which would be taken by ip_output(), as this one will loop back to
499 1.1 hwr * us. If the interface is p2p as a--->b, then a routing entry exists
500 1.1 hwr * If we now send a packet to b (e.g. ping b), this will come down here
501 1.1 hwr * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
502 1.1 hwr * if_gre.
503 1.1 hwr * Goal here is to compute a route to b that is less specific than
504 1.1 hwr * a-->b. We know that this one exists as in normal operation we have
505 1.1 hwr * at least a default route which matches.
506 1.1 hwr */
507 1.1 hwr
508 1.8 explorer void
509 1.8 explorer gre_compute_route(struct gre_softc *sc)
510 1.1 hwr {
511 1.1 hwr struct route *ro;
512 1.8 explorer u_int32_t a, b, c;
513 1.1 hwr
514 1.8 explorer ro = &sc->route;
515 1.1 hwr
516 1.8 explorer memset(ro, 0, sizeof(struct route));
517 1.8 explorer ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
518 1.8 explorer ro->ro_dst.sa_family = AF_INET;
519 1.8 explorer ro->ro_dst.sa_len = sizeof(ro->ro_dst);
520 1.8 explorer
521 1.1 hwr /*
522 1.1 hwr * toggle last bit, so our interface is not found, but a less
523 1.1 hwr * specific route. I'd rather like to specify a shorter mask,
524 1.1 hwr * but this is not possible. Should work though. XXX
525 1.1 hwr * there is a simpler way ...
526 1.1 hwr */
527 1.8 explorer if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
528 1.8 explorer a = ntohl(sc->g_dst.s_addr);
529 1.8 explorer b = a & 0x01;
530 1.8 explorer c = a & 0xfffffffe;
531 1.8 explorer b = b ^ 0x01;
532 1.8 explorer a = b | c;
533 1.8 explorer ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
534 1.8 explorer = htonl(a);
535 1.8 explorer }
536 1.1 hwr
537 1.1 hwr #ifdef DIAGNOSTIC
538 1.8 explorer printf("%s: searching a route to ", sc->sc_if.if_xname);
539 1.8 explorer gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
540 1.1 hwr #endif
541 1.1 hwr
542 1.1 hwr rtalloc(ro);
543 1.1 hwr
544 1.1 hwr /*
545 1.1 hwr * now change it back - else ip_output will just drop
546 1.1 hwr * the route and search one to this interface ...
547 1.1 hwr */
548 1.8 explorer if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
549 1.8 explorer ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
550 1.1 hwr
551 1.1 hwr #ifdef DIAGNOSTIC
552 1.8 explorer printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
553 1.8 explorer gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
554 1.8 explorer printf("\n");
555 1.1 hwr #endif
556 1.1 hwr }
557 1.1 hwr
558 1.3 hwr /*
559 1.3 hwr * do a checksum of a buffer - much like in_cksum, which operates on
560 1.3 hwr * mbufs.
561 1.3 hwr */
562 1.3 hwr
563 1.3 hwr u_short
564 1.8 explorer gre_in_cksum(u_short *p, u_int len)
565 1.3 hwr {
566 1.3 hwr u_int sum = 0;
567 1.3 hwr int nwords = len >> 1;
568 1.3 hwr
569 1.3 hwr while (nwords-- != 0)
570 1.3 hwr sum += *p++;
571 1.3 hwr
572 1.3 hwr if (len & 1) {
573 1.3 hwr union {
574 1.3 hwr u_short w;
575 1.3 hwr u_char c[2];
576 1.3 hwr } u;
577 1.3 hwr u.c[0] = *(u_char *)p;
578 1.3 hwr u.c[1] = 0;
579 1.3 hwr sum += u.w;
580 1.3 hwr }
581 1.3 hwr
582 1.3 hwr /* end-around-carry */
583 1.3 hwr sum = (sum >> 16) + (sum & 0xffff);
584 1.3 hwr sum += (sum >> 16);
585 1.3 hwr return (~sum);
586 1.3 hwr }
587 1.3 hwr
588 1.3 hwr
589 1.1 hwr /* while testing ... */
590 1.1 hwr #ifdef DIAGNOSTIC
591 1.1 hwr void
592 1.8 explorer gre_inet_ntoa(struct in_addr in)
593 1.1 hwr {
594 1.8 explorer char *p;
595 1.1 hwr
596 1.8 explorer p = (char *)∈
597 1.1 hwr #define UC(b) (((int)b)&0xff)
598 1.8 explorer printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
599 1.1 hwr }
600 1.1 hwr
601 1.1 hwr #endif
602 1.1 hwr #endif
603 1.1 hwr
604