if_gre.c revision 1.6 1 1.6 hwr /* $NetBSD: if_gre.c,v 1.6 1999/01/26 21:21:14 hwr 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.1 hwr void greattach(void)
124 1.1 hwr {
125 1.1 hwr
126 1.1 hwr register struct gre_softc *sc;
127 1.1 hwr register int i;
128 1.1 hwr
129 1.1 hwr i = 0 ;
130 1.1 hwr 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.1 hwr sc->sc_if.if_collisions=0;
141 1.1 hwr sc->sc_if.if_ierrors=0;
142 1.1 hwr sc->sc_if.if_oerrors=0;
143 1.1 hwr sc->sc_if.if_ipackets=0;
144 1.1 hwr sc->sc_if.if_opackets=0;
145 1.1 hwr sc->g_dst.s_addr=sc->g_src.s_addr=INADDR_ANY;
146 1.1 hwr 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.1 hwr struct ip ip_h;
164 1.3 hwr struct mobile_h mob_h;
165 1.1 hwr
166 1.1 hwr int
167 1.1 hwr gre_output(ifp, m, dst, rt)
168 1.1 hwr struct ifnet *ifp;
169 1.1 hwr register struct mbuf *m;
170 1.1 hwr struct sockaddr *dst;
171 1.1 hwr register struct rtentry *rt;
172 1.1 hwr {
173 1.1 hwr int error=0;
174 1.1 hwr struct gre_softc *sc=(struct gre_softc *)(ifp->if_softc);
175 1.1 hwr struct greip *gh;
176 1.1 hwr struct ip *inp;
177 1.3 hwr u_char ttl,osrc;
178 1.3 hwr u_short etype=0;
179 1.3 hwr
180 1.1 hwr
181 1.1 hwr gh=NULL;
182 1.1 hwr inp=NULL;
183 1.3 hwr osrc=0;
184 1.1 hwr
185 1.1 hwr #if 0
186 1.1 hwr #if NBPFILTER >0
187 1.1 hwr
188 1.1 hwr if (sc->gre_bpf) {
189 1.1 hwr /* see comment of other if_foo.c files */
190 1.1 hwr struct mbuf m0;
191 1.1 hwr u_int af = dst->sa_family;
192 1.1 hwr
193 1.1 hwr m0.m_next =m;
194 1.1 hwr m0.m_len =4;
195 1.1 hwr m0.m_data = (char *)⁡
196 1.1 hwr
197 1.1 hwr bpf_mtap(ifp->if_bpf, &m0);
198 1.1 hwr }
199 1.1 hwr #endif
200 1.1 hwr #endif
201 1.1 hwr
202 1.1 hwr ttl=255;
203 1.1 hwr
204 1.5 thorpej if (sc->g_proto == IPPROTO_MOBILE) {
205 1.3 hwr if (dst->sa_family == AF_INET) {
206 1.3 hwr struct mbuf *m0;
207 1.3 hwr int msiz;
208 1.3 hwr
209 1.3 hwr inp=mtod(m,struct ip *);
210 1.3 hwr
211 1.3 hwr memset(&mob_h,0,MOB_H_SIZ_L);
212 1.3 hwr mob_h.proto=(inp->ip_p)<<8;
213 1.3 hwr mob_h.odst=inp->ip_dst.s_addr;
214 1.3 hwr inp->ip_dst.s_addr=sc->g_dst.s_addr;
215 1.3 hwr
216 1.3 hwr /*
217 1.3 hwr * If the packet comes from our host, we only change the
218 1.3 hwr * destination address in the IP header. Else we also need
219 1.3 hwr * to save and change the source
220 1.3 hwr */
221 1.3 hwr
222 1.3 hwr if (in_hosteq(inp->ip_src, sc->g_src)) {
223 1.3 hwr msiz=MOB_H_SIZ_S;
224 1.3 hwr } else {
225 1.3 hwr mob_h.proto |= MOB_H_SBIT;
226 1.3 hwr mob_h.osrc=inp->ip_src.s_addr;
227 1.3 hwr inp->ip_src.s_addr=sc->g_src.s_addr;
228 1.3 hwr msiz=MOB_H_SIZ_L;
229 1.3 hwr }
230 1.3 hwr HTONS(mob_h.proto);
231 1.3 hwr mob_h.hcrc=gre_in_cksum((u_short *)&mob_h,msiz);
232 1.3 hwr
233 1.3 hwr if ((m->m_data - msiz) < m->m_pktdat) {
234 1.3 hwr /* need new mbuf */
235 1.3 hwr MGETHDR(m0, M_DONTWAIT, MT_HEADER);
236 1.3 hwr if (m0==NULL) {
237 1.3 hwr IF_DROP(&ifp->if_snd);
238 1.3 hwr m_freem(m);
239 1.3 hwr return(ENOBUFS);
240 1.3 hwr }
241 1.3 hwr m0->m_next=m;
242 1.3 hwr m->m_data += sizeof(struct ip);
243 1.3 hwr m->m_len -= sizeof(struct ip);
244 1.3 hwr m0->m_pkthdr.len=m->m_pkthdr.len+msiz;
245 1.3 hwr m0->m_len = msiz + sizeof(struct ip);
246 1.3 hwr m0->m_data += max_linkhdr;
247 1.3 hwr memcpy(mtod(m0, caddr_t), (caddr_t) inp, sizeof(struct ip));
248 1.3 hwr m=m0;
249 1.3 hwr } else { /* we have some spave left in the old one */
250 1.3 hwr m->m_data-=msiz;
251 1.3 hwr m->m_len+=msiz;
252 1.3 hwr m->m_pkthdr.len+=msiz;
253 1.3 hwr ovbcopy((caddr_t) inp, mtod(m, caddr_t), sizeof(struct ip));
254 1.3 hwr }
255 1.3 hwr inp=mtod(m,struct ip *);
256 1.3 hwr memcpy((caddr_t) (inp+1), &mob_h, (unsigned) msiz);
257 1.3 hwr NTOHS(inp->ip_len);
258 1.3 hwr 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.3 hwr 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.1 hwr inp=mtod(m,struct ip *);
268 1.1 hwr ttl=inp->ip_ttl;
269 1.1 hwr etype=ETHERTYPE_IP;
270 1.1 hwr break;
271 1.1 hwr #ifdef NETATALK
272 1.1 hwr case AF_APPLETALK:
273 1.1 hwr 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.1 hwr 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.1 hwr return(EAFNOSUPPORT);
285 1.1 hwr }
286 1.1 hwr M_PREPEND(m,sizeof(struct greip),M_DONTWAIT);
287 1.1 hwr } else {
288 1.1 hwr error= EINVAL;
289 1.1 hwr IF_DROP(&ifp->if_snd);
290 1.1 hwr m_freem(m);
291 1.1 hwr 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.1 hwr return(ENOBUFS);
298 1.1 hwr }
299 1.1 hwr
300 1.1 hwr gh=mtod(m,struct greip *);
301 1.1 hwr 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.1 hwr memset((void*)&gh->gi_g,0, sizeof(struct gre_h));
305 1.1 hwr 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.3 hwr ((struct ip*)gh)->ip_ttl=ttl;
314 1.3 hwr ((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.1 hwr ifp->if_obytes+=m->m_pkthdr.len;
320 1.1 hwr /* send it off */
321 1.1 hwr error=ip_output(m,NULL,&sc->route,0,NULL);
322 1.1 hwr if (error) {
323 1.1 hwr ifp->if_oerrors++;
324 1.1 hwr }
325 1.1 hwr return(error);
326 1.1 hwr
327 1.1 hwr }
328 1.1 hwr
329 1.1 hwr int
330 1.1 hwr gre_ioctl(ifp, cmd, data)
331 1.1 hwr struct ifnet *ifp;
332 1.1 hwr u_long cmd;
333 1.1 hwr caddr_t data;
334 1.1 hwr {
335 1.1 hwr
336 1.1 hwr register struct ifaddr *ifa = (struct ifaddr *)data;
337 1.1 hwr register struct ifreq *ifr = (struct ifreq *)data;
338 1.1 hwr register struct in_ifaddr *ia = (struct in_ifaddr *)data;
339 1.1 hwr register struct gre_softc *sc = ifp->if_softc;
340 1.1 hwr int s;
341 1.1 hwr struct sockaddr_in si;
342 1.1 hwr struct sockaddr *sa =NULL;
343 1.1 hwr int error;
344 1.1 hwr
345 1.1 hwr error= 0;
346 1.1 hwr
347 1.1 hwr s = splimp();
348 1.1 hwr switch(cmd) {
349 1.1 hwr case SIOCSIFADDR:
350 1.1 hwr case SIOCSIFDSTADDR:
351 1.1 hwr /*
352 1.1 hwr * set tunnel endpoints in case that we "only"
353 1.1 hwr * have ip over ip encapsulation. This allows to
354 1.1 hwr * set tunnel endpoints with ifconfig.
355 1.1 hwr */
356 1.1 hwr if (ifa->ifa_addr->sa_family == AF_INET) {
357 1.1 hwr sa = ifa->ifa_addr;
358 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
359 1.1 hwr sc->g_dst = ia->ia_dstaddr.sin_addr;
360 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
361 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
362 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
363 1.1 hwr RTFREE(sc->route.ro_rt);
364 1.1 hwr gre_compute_route(sc);
365 1.1 hwr ifp->if_flags |= IFF_UP;
366 1.1 hwr }
367 1.1 hwr }
368 1.1 hwr break;
369 1.1 hwr case SIOCSIFFLAGS:
370 1.1 hwr if ((sc->g_dst.s_addr== INADDR_ANY) ||
371 1.1 hwr (sc->g_src.s_addr== INADDR_ANY))
372 1.1 hwr ifp->if_flags &= ~IFF_UP;
373 1.1 hwr
374 1.3 hwr switch(ifr->ifr_flags & LINK_MASK) {
375 1.3 hwr case IFF_LINK0:
376 1.3 hwr sc->g_proto = IPPROTO_GRE;
377 1.3 hwr ifp->if_flags |= IFF_LINK0;
378 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
379 1.3 hwr break;
380 1.3 hwr case IFF_LINK2:
381 1.3 hwr sc->g_proto = IPPROTO_MOBILE;
382 1.3 hwr ifp->if_flags |= IFF_LINK2;
383 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1);
384 1.3 hwr break;
385 1.1 hwr }
386 1.1 hwr break;
387 1.1 hwr case SIOCSIFMTU:
388 1.1 hwr if (ifr->ifr_mtu > GREMTU || ifr->ifr_mtu < 576) {
389 1.1 hwr error = EINVAL;
390 1.1 hwr break;
391 1.1 hwr }
392 1.1 hwr ifp->if_mtu = ifr->ifr_mtu;
393 1.1 hwr break;
394 1.1 hwr case SIOCGIFMTU:
395 1.1 hwr ifr->ifr_mtu = sc->sc_if.if_mtu;
396 1.1 hwr break;
397 1.1 hwr case SIOCADDMULTI:
398 1.1 hwr case SIOCDELMULTI:
399 1.1 hwr if (ifr == 0 ) {
400 1.1 hwr error = EAFNOSUPPORT;
401 1.1 hwr break;
402 1.1 hwr }
403 1.1 hwr switch(ifr->ifr_addr.sa_family) {
404 1.1 hwr #ifdef INET
405 1.1 hwr case AF_INET:
406 1.1 hwr break;
407 1.1 hwr #endif
408 1.1 hwr default:
409 1.1 hwr error = EAFNOSUPPORT;
410 1.1 hwr break;
411 1.1 hwr }
412 1.1 hwr break;
413 1.1 hwr case GRESPROTO:
414 1.1 hwr sc->g_proto = ifr->ifr_flags;
415 1.1 hwr switch (sc->g_proto) {
416 1.3 hwr case IPPROTO_GRE :
417 1.3 hwr ifp->if_flags |= IFF_LINK0;
418 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
419 1.1 hwr break;
420 1.3 hwr case IPPROTO_MOBILE :
421 1.3 hwr ifp->if_flags |= IFF_LINK2;
422 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
423 1.1 hwr break;
424 1.1 hwr default:
425 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
426 1.1 hwr }
427 1.1 hwr break;
428 1.1 hwr case GREGPROTO:
429 1.1 hwr ifr->ifr_flags = sc->g_proto;
430 1.1 hwr break;
431 1.1 hwr case GRESADDRS:
432 1.1 hwr case GRESADDRD:
433 1.1 hwr /*
434 1.1 hwr * set tunnel endpoints, compute a less specific route
435 1.1 hwr * to the remote end and mark if as up
436 1.1 hwr */
437 1.1 hwr sa = &ifr->ifr_addr;
438 1.1 hwr if (cmd == GRESADDRS )
439 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
440 1.1 hwr if (cmd == GRESADDRD )
441 1.1 hwr sc->g_dst = (satosin(sa))->sin_addr;
442 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
443 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
444 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
445 1.1 hwr RTFREE(sc->route.ro_rt);
446 1.1 hwr gre_compute_route(sc);
447 1.1 hwr ifp->if_flags |= IFF_UP;
448 1.1 hwr }
449 1.1 hwr break;
450 1.1 hwr case GREGADDRS:
451 1.1 hwr si.sin_addr.s_addr = sc->g_src.s_addr;
452 1.1 hwr sa=sintosa(&si);
453 1.1 hwr ifr->ifr_addr = *sa;
454 1.1 hwr break;
455 1.1 hwr case GREGADDRD:
456 1.1 hwr si.sin_addr.s_addr = sc->g_dst.s_addr;
457 1.1 hwr sa=sintosa(&si);
458 1.1 hwr ifr->ifr_addr = *sa;
459 1.1 hwr break;
460 1.1 hwr default:
461 1.1 hwr error = EINVAL;
462 1.1 hwr }
463 1.1 hwr
464 1.1 hwr splx(s);
465 1.1 hwr return(error);
466 1.1 hwr }
467 1.1 hwr
468 1.1 hwr /*
469 1.1 hwr * computes a route to our destination that is not the one
470 1.1 hwr * which would be taken by ip_output(), as this one will loop back to
471 1.1 hwr * us. If the interface is p2p as a--->b, then a routing entry exists
472 1.1 hwr * If we now send a packet to b (e.g. ping b), this will come down here
473 1.1 hwr * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
474 1.1 hwr * if_gre.
475 1.1 hwr * Goal here is to compute a route to b that is less specific than
476 1.1 hwr * a-->b. We know that this one exists as in normal operation we have
477 1.1 hwr * at least a default route which matches.
478 1.1 hwr */
479 1.1 hwr
480 1.1 hwr void gre_compute_route(struct gre_softc *sc)
481 1.1 hwr {
482 1.1 hwr struct route *ro;
483 1.1 hwr u_int32_t a,b,c;
484 1.1 hwr
485 1.1 hwr ro=&sc->route;
486 1.1 hwr
487 1.1 hwr memset(ro,0,sizeof(struct route));
488 1.1 hwr ((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst;
489 1.1 hwr ro->ro_dst.sa_family=AF_INET;
490 1.1 hwr ro->ro_dst.sa_len=sizeof(ro->ro_dst);
491 1.1 hwr /*
492 1.1 hwr * toggle last bit, so our interface is not found, but a less
493 1.1 hwr * specific route. I'd rather like to specify a shorter mask,
494 1.1 hwr * but this is not possible. Should work though. XXX
495 1.1 hwr * there is a simpler way ...
496 1.1 hwr */
497 1.1 hwr a= ntohl(sc->g_dst.s_addr);
498 1.1 hwr b= a & 0x01;
499 1.1 hwr c= a & 0xfffffffe;
500 1.1 hwr b = b ^ 0x01;
501 1.1 hwr a = b | c;
502 1.1 hwr ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr=htonl(a);
503 1.1 hwr
504 1.1 hwr #ifdef DIAGNOSTIC
505 1.1 hwr printf("%s: searching a route to ",sc->sc_if.if_xname);
506 1.3 hwr gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
507 1.1 hwr #endif
508 1.1 hwr
509 1.1 hwr rtalloc(ro);
510 1.1 hwr
511 1.1 hwr /*
512 1.1 hwr * now change it back - else ip_output will just drop
513 1.1 hwr * the route and search one to this interface ...
514 1.1 hwr */
515 1.1 hwr ((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst;
516 1.1 hwr
517 1.1 hwr #ifdef DIAGNOSTIC
518 1.1 hwr printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
519 1.3 hwr gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
520 1.1 hwr printf("\n");
521 1.1 hwr #endif
522 1.1 hwr }
523 1.1 hwr
524 1.3 hwr /*
525 1.3 hwr * do a checksum of a buffer - much like in_cksum, which operates on
526 1.3 hwr * mbufs.
527 1.3 hwr */
528 1.3 hwr
529 1.3 hwr u_short
530 1.3 hwr gre_in_cksum(p, len)
531 1.3 hwr u_short *p;
532 1.3 hwr 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.3 hwr gre_inet_ntoa(in)
561 1.1 hwr struct in_addr in;
562 1.1 hwr {
563 1.1 hwr register char *p;
564 1.1 hwr
565 1.1 hwr p = (char *)∈
566 1.1 hwr #define UC(b) (((int)b)&0xff)
567 1.1 hwr printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
568 1.1 hwr }
569 1.1 hwr
570 1.1 hwr #endif
571 1.1 hwr #endif
572 1.1 hwr
573