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