if_gre.c revision 1.3 1 1.3 hwr /* $NetBSD: if_gre.c,v 1.3 1998/09/30 05:59:27 hwr Exp $ */
2 1.1 hwr /*
3 1.1 hwr * (c) 1998 The NetBSD Foundation, Inc.
4 1.1 hwr * All rights reserved.
5 1.1 hwr *
6 1.1 hwr * This code is derived from software contributed to The NetBSD Foundation
7 1.1 hwr * by Heiko W.Rupp <hwr (at) pilhuhn.de>
8 1.1 hwr *
9 1.1 hwr * Redistribution and use in source and binary forms, with or without
10 1.1 hwr * modification, are permitted provided that the following conditions
11 1.1 hwr * are met:
12 1.1 hwr * 1. Redistributions of source code must retain the above copyright
13 1.1 hwr * notice, this list of conditions and the following disclaimer.
14 1.1 hwr * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 hwr * notice, this list of conditions and the following disclaimer in the
16 1.1 hwr * documentation and/or other materials provided with the distribution.
17 1.1 hwr * 3. All advertising materials mentioning features or use of this software
18 1.1 hwr * must display the following acknowledgement:
19 1.1 hwr * This product includes software developed by the NetBSD
20 1.1 hwr * Foundation, Inc. and its contributors.
21 1.1 hwr * 4. Neither the name of The NetBSD Foundation nor the names of its
22 1.1 hwr * contributors may be used to endorse or promote products derived
23 1.1 hwr * from this software without specific prior written permission.
24 1.1 hwr *
25 1.1 hwr * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 1.1 hwr * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.1 hwr * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.1 hwr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 1.1 hwr * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.1 hwr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.1 hwr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.1 hwr * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.1 hwr * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.1 hwr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.1 hwr * POSSIBILITY OF SUCH DAMAGE.
36 1.1 hwr */
37 1.1 hwr
38 1.1 hwr /*
39 1.1 hwr * Encapsulate L3 protocols into IP
40 1.1 hwr * See RFC 1701 and 1702 for more details.
41 1.1 hwr * If_gre is compatible with Cisco GRE tunnels, so you can
42 1.1 hwr * have a NetBSD box as the other end of a tunnel interface of a Cisco
43 1.1 hwr * router. See gre(4) for more details.
44 1.3 hwr * Also supported: IP in IP encaps (proto 4) as of RFC 2003
45 1.3 hwr * 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.1 hwr #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.1 hwr bpfattach(&sc->gre_bpf, &sc->sc_if, DLT_NULL, 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.3 hwr * given by sc->g_proto. See also RFC 1701, RFC 2003 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.1 hwr if (sc->g_proto == IPPROTO_IPIP ) {
205 1.1 hwr if (dst->sa_family == AF_INET) {
206 1.1 hwr inp=mtod(m,struct ip *);
207 1.1 hwr ttl=inp->ip_ttl;
208 1.1 hwr etype=ETHERTYPE_IP;
209 1.1 hwr M_PREPEND(m,sizeof(struct ip),M_DONTWAIT);
210 1.1 hwr } else {
211 1.1 hwr IF_DROP(&ifp->if_snd);
212 1.1 hwr m_freem(m);
213 1.1 hwr return(EINVAL);
214 1.1 hwr }
215 1.3 hwr #if 1
216 1.3 hwr } else if (sc->g_proto == IPPROTO_MOBILE) {
217 1.3 hwr if (dst->sa_family == AF_INET) {
218 1.3 hwr struct mbuf *m0;
219 1.3 hwr int msiz;
220 1.3 hwr
221 1.3 hwr inp=mtod(m,struct ip *);
222 1.3 hwr
223 1.3 hwr memset(&mob_h,0,MOB_H_SIZ_L);
224 1.3 hwr mob_h.proto=(inp->ip_p)<<8;
225 1.3 hwr mob_h.odst=inp->ip_dst.s_addr;
226 1.3 hwr inp->ip_dst.s_addr=sc->g_dst.s_addr;
227 1.3 hwr
228 1.3 hwr /*
229 1.3 hwr * If the packet comes from our host, we only change the
230 1.3 hwr * destination address in the IP header. Else we also need
231 1.3 hwr * to save and change the source
232 1.3 hwr */
233 1.3 hwr
234 1.3 hwr if (in_hosteq(inp->ip_src, sc->g_src)) {
235 1.3 hwr msiz=MOB_H_SIZ_S;
236 1.3 hwr } else {
237 1.3 hwr mob_h.proto |= MOB_H_SBIT;
238 1.3 hwr mob_h.osrc=inp->ip_src.s_addr;
239 1.3 hwr inp->ip_src.s_addr=sc->g_src.s_addr;
240 1.3 hwr msiz=MOB_H_SIZ_L;
241 1.3 hwr }
242 1.3 hwr HTONS(mob_h.proto);
243 1.3 hwr mob_h.hcrc=gre_in_cksum((u_short *)&mob_h,msiz);
244 1.3 hwr
245 1.3 hwr if ((m->m_data - msiz) < m->m_pktdat) {
246 1.3 hwr /* need new mbuf */
247 1.3 hwr MGETHDR(m0, M_DONTWAIT, MT_HEADER);
248 1.3 hwr if (m0==NULL) {
249 1.3 hwr IF_DROP(&ifp->if_snd);
250 1.3 hwr m_freem(m);
251 1.3 hwr return(ENOBUFS);
252 1.3 hwr }
253 1.3 hwr m0->m_next=m;
254 1.3 hwr m->m_data += sizeof(struct ip);
255 1.3 hwr m->m_len -= sizeof(struct ip);
256 1.3 hwr m0->m_pkthdr.len=m->m_pkthdr.len+msiz;
257 1.3 hwr m0->m_len = msiz + sizeof(struct ip);
258 1.3 hwr m0->m_data += max_linkhdr;
259 1.3 hwr memcpy(mtod(m0, caddr_t), (caddr_t) inp, sizeof(struct ip));
260 1.3 hwr m=m0;
261 1.3 hwr } else { /* we have some spave left in the old one */
262 1.3 hwr m->m_data-=msiz;
263 1.3 hwr m->m_len+=msiz;
264 1.3 hwr m->m_pkthdr.len+=msiz;
265 1.3 hwr ovbcopy((caddr_t) inp, mtod(m, caddr_t), sizeof(struct ip));
266 1.3 hwr }
267 1.3 hwr inp=mtod(m,struct ip *);
268 1.3 hwr memcpy((caddr_t) (inp+1), &mob_h, (unsigned) msiz);
269 1.3 hwr NTOHS(inp->ip_len);
270 1.3 hwr inp->ip_len+=msiz;
271 1.3 hwr } else { /* AF_INET */
272 1.3 hwr IF_DROP(&ifp->if_snd);
273 1.3 hwr m_freem(m);
274 1.3 hwr return(EINVAL);
275 1.3 hwr }
276 1.3 hwr #endif
277 1.1 hwr } else if (sc->g_proto == IPPROTO_GRE) {
278 1.1 hwr switch(dst->sa_family) {
279 1.1 hwr case AF_INET:
280 1.1 hwr inp=mtod(m,struct ip *);
281 1.1 hwr ttl=inp->ip_ttl;
282 1.1 hwr etype=ETHERTYPE_IP;
283 1.1 hwr break;
284 1.1 hwr #ifdef NETATALK
285 1.1 hwr case AF_APPLETALK:
286 1.1 hwr etype=ETHERTYPE_ATALK;
287 1.1 hwr break;
288 1.1 hwr #endif
289 1.1 hwr #ifdef NS
290 1.1 hwr case AF_NS:
291 1.1 hwr etype=ETHERTYPE_NS;
292 1.1 hwr break;
293 1.1 hwr #endif
294 1.1 hwr default:
295 1.1 hwr IF_DROP(&ifp->if_snd);
296 1.1 hwr m_freem(m);
297 1.1 hwr return(EAFNOSUPPORT);
298 1.1 hwr }
299 1.1 hwr M_PREPEND(m,sizeof(struct greip),M_DONTWAIT);
300 1.1 hwr } else {
301 1.1 hwr error= EINVAL;
302 1.1 hwr IF_DROP(&ifp->if_snd);
303 1.1 hwr m_freem(m);
304 1.1 hwr return(error);
305 1.1 hwr }
306 1.1 hwr
307 1.1 hwr
308 1.1 hwr if (m == NULL) {
309 1.1 hwr IF_DROP(&ifp->if_snd);
310 1.1 hwr return(ENOBUFS);
311 1.1 hwr }
312 1.1 hwr
313 1.1 hwr gh=mtod(m,struct greip *);
314 1.1 hwr if (sc->g_proto == IPPROTO_GRE){
315 1.1 hwr /* we don't have any GRE flags for now */
316 1.1 hwr
317 1.1 hwr memset((void*)&gh->gi_g,0, sizeof(struct gre_h));
318 1.1 hwr gh->gi_ptype=htons(etype);
319 1.1 hwr }
320 1.1 hwr
321 1.1 hwr /* rest is same for GRE and IPIP and all inner protos */
322 1.1 hwr
323 1.1 hwr gh->gi_pr = sc->g_proto;
324 1.3 hwr if (sc->g_proto != IPPROTO_MOBILE) {
325 1.3 hwr gh->gi_src = sc->g_src;
326 1.3 hwr gh->gi_dst = sc->g_dst;
327 1.3 hwr ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
328 1.3 hwr ((struct ip*)gh)->ip_ttl=ttl;
329 1.3 hwr ((struct ip*)gh)->ip_tos=inp->ip_tos;
330 1.3 hwr gh->gi_len = m->m_pkthdr.len;
331 1.3 hwr }
332 1.1 hwr
333 1.1 hwr ifp->if_opackets++;
334 1.1 hwr ifp->if_obytes+=m->m_pkthdr.len;
335 1.1 hwr /* send it off */
336 1.1 hwr error=ip_output(m,NULL,&sc->route,0,NULL);
337 1.1 hwr if (error) {
338 1.1 hwr ifp->if_oerrors++;
339 1.1 hwr }
340 1.1 hwr return(error);
341 1.1 hwr
342 1.1 hwr }
343 1.1 hwr
344 1.1 hwr int
345 1.1 hwr gre_ioctl(ifp, cmd, data)
346 1.1 hwr struct ifnet *ifp;
347 1.1 hwr u_long cmd;
348 1.1 hwr caddr_t data;
349 1.1 hwr {
350 1.1 hwr
351 1.1 hwr register struct ifaddr *ifa = (struct ifaddr *)data;
352 1.1 hwr register struct ifreq *ifr = (struct ifreq *)data;
353 1.1 hwr register struct in_ifaddr *ia = (struct in_ifaddr *)data;
354 1.1 hwr register struct gre_softc *sc = ifp->if_softc;
355 1.1 hwr int s;
356 1.1 hwr struct sockaddr_in si;
357 1.1 hwr struct sockaddr *sa =NULL;
358 1.1 hwr int error;
359 1.1 hwr
360 1.1 hwr error= 0;
361 1.1 hwr
362 1.1 hwr s = splimp();
363 1.1 hwr switch(cmd) {
364 1.1 hwr case SIOCSIFADDR:
365 1.1 hwr case SIOCSIFDSTADDR:
366 1.1 hwr /*
367 1.1 hwr * set tunnel endpoints in case that we "only"
368 1.1 hwr * have ip over ip encapsulation. This allows to
369 1.1 hwr * set tunnel endpoints with ifconfig.
370 1.1 hwr */
371 1.1 hwr if (ifa->ifa_addr->sa_family == AF_INET) {
372 1.1 hwr sa = ifa->ifa_addr;
373 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
374 1.1 hwr sc->g_dst = ia->ia_dstaddr.sin_addr;
375 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
376 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
377 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
378 1.1 hwr RTFREE(sc->route.ro_rt);
379 1.1 hwr gre_compute_route(sc);
380 1.1 hwr ifp->if_flags |= IFF_UP;
381 1.1 hwr }
382 1.1 hwr }
383 1.1 hwr break;
384 1.1 hwr case SIOCSIFFLAGS:
385 1.1 hwr if ((sc->g_dst.s_addr== INADDR_ANY) ||
386 1.1 hwr (sc->g_src.s_addr== INADDR_ANY))
387 1.1 hwr ifp->if_flags &= ~IFF_UP;
388 1.1 hwr
389 1.3 hwr switch(ifr->ifr_flags & LINK_MASK) {
390 1.3 hwr case IFF_LINK0:
391 1.3 hwr sc->g_proto = IPPROTO_GRE;
392 1.3 hwr ifp->if_flags |= IFF_LINK0;
393 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
394 1.3 hwr break;
395 1.3 hwr case IFF_LINK1:
396 1.3 hwr sc->g_proto = IPPROTO_IPIP;
397 1.3 hwr ifp->if_flags |= IFF_LINK1;
398 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|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.1 hwr if (ifr->ifr_mtu > GREMTU || ifr->ifr_mtu < 576) {
409 1.1 hwr error = EINVAL;
410 1.1 hwr break;
411 1.1 hwr }
412 1.1 hwr ifp->if_mtu = ifr->ifr_mtu;
413 1.1 hwr break;
414 1.1 hwr case SIOCGIFMTU:
415 1.1 hwr ifr->ifr_mtu = sc->sc_if.if_mtu;
416 1.1 hwr break;
417 1.1 hwr case SIOCADDMULTI:
418 1.1 hwr case SIOCDELMULTI:
419 1.1 hwr if (ifr == 0 ) {
420 1.1 hwr error = EAFNOSUPPORT;
421 1.1 hwr break;
422 1.1 hwr }
423 1.1 hwr switch(ifr->ifr_addr.sa_family) {
424 1.1 hwr #ifdef INET
425 1.1 hwr case AF_INET:
426 1.1 hwr break;
427 1.1 hwr #endif
428 1.1 hwr default:
429 1.1 hwr error = EAFNOSUPPORT;
430 1.1 hwr break;
431 1.1 hwr }
432 1.1 hwr break;
433 1.1 hwr case GRESPROTO:
434 1.1 hwr sc->g_proto = ifr->ifr_flags;
435 1.1 hwr switch (sc->g_proto) {
436 1.3 hwr case IPPROTO_GRE :
437 1.3 hwr ifp->if_flags |= IFF_LINK0;
438 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
439 1.3 hwr break;
440 1.1 hwr case IPPROTO_IPIP :
441 1.1 hwr ifp->if_flags |= IFF_LINK1;
442 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK2);
443 1.1 hwr break;
444 1.3 hwr case IPPROTO_MOBILE :
445 1.3 hwr ifp->if_flags |= IFF_LINK2;
446 1.3 hwr ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
447 1.1 hwr break;
448 1.1 hwr default:
449 1.3 hwr ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
450 1.1 hwr }
451 1.1 hwr break;
452 1.1 hwr case GREGPROTO:
453 1.1 hwr ifr->ifr_flags = sc->g_proto;
454 1.1 hwr break;
455 1.1 hwr case GRESADDRS:
456 1.1 hwr case GRESADDRD:
457 1.1 hwr /*
458 1.1 hwr * set tunnel endpoints, compute a less specific route
459 1.1 hwr * to the remote end and mark if as up
460 1.1 hwr */
461 1.1 hwr sa = &ifr->ifr_addr;
462 1.1 hwr if (cmd == GRESADDRS )
463 1.1 hwr sc->g_src = (satosin(sa))->sin_addr;
464 1.1 hwr if (cmd == GRESADDRD )
465 1.1 hwr sc->g_dst = (satosin(sa))->sin_addr;
466 1.1 hwr if ((sc->g_src.s_addr != INADDR_ANY) &&
467 1.1 hwr (sc->g_dst.s_addr != INADDR_ANY)) {
468 1.1 hwr if (sc->route.ro_rt != 0) /* free old route */
469 1.1 hwr RTFREE(sc->route.ro_rt);
470 1.1 hwr gre_compute_route(sc);
471 1.1 hwr ifp->if_flags |= IFF_UP;
472 1.1 hwr }
473 1.1 hwr break;
474 1.1 hwr case GREGADDRS:
475 1.1 hwr si.sin_addr.s_addr = sc->g_src.s_addr;
476 1.1 hwr sa=sintosa(&si);
477 1.1 hwr ifr->ifr_addr = *sa;
478 1.1 hwr break;
479 1.1 hwr case GREGADDRD:
480 1.1 hwr si.sin_addr.s_addr = sc->g_dst.s_addr;
481 1.1 hwr sa=sintosa(&si);
482 1.1 hwr ifr->ifr_addr = *sa;
483 1.1 hwr break;
484 1.1 hwr default:
485 1.1 hwr error = EINVAL;
486 1.1 hwr }
487 1.1 hwr
488 1.1 hwr splx(s);
489 1.1 hwr return(error);
490 1.1 hwr }
491 1.1 hwr
492 1.1 hwr /*
493 1.1 hwr * computes a route to our destination that is not the one
494 1.1 hwr * which would be taken by ip_output(), as this one will loop back to
495 1.1 hwr * us. If the interface is p2p as a--->b, then a routing entry exists
496 1.1 hwr * If we now send a packet to b (e.g. ping b), this will come down here
497 1.1 hwr * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
498 1.1 hwr * if_gre.
499 1.1 hwr * Goal here is to compute a route to b that is less specific than
500 1.1 hwr * a-->b. We know that this one exists as in normal operation we have
501 1.1 hwr * at least a default route which matches.
502 1.1 hwr */
503 1.1 hwr
504 1.1 hwr void gre_compute_route(struct gre_softc *sc)
505 1.1 hwr {
506 1.1 hwr struct route *ro;
507 1.1 hwr u_int32_t a,b,c;
508 1.1 hwr
509 1.1 hwr ro=&sc->route;
510 1.1 hwr
511 1.1 hwr memset(ro,0,sizeof(struct route));
512 1.1 hwr ((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst;
513 1.1 hwr ro->ro_dst.sa_family=AF_INET;
514 1.1 hwr ro->ro_dst.sa_len=sizeof(ro->ro_dst);
515 1.1 hwr /*
516 1.1 hwr * toggle last bit, so our interface is not found, but a less
517 1.1 hwr * specific route. I'd rather like to specify a shorter mask,
518 1.1 hwr * but this is not possible. Should work though. XXX
519 1.1 hwr * there is a simpler way ...
520 1.1 hwr */
521 1.1 hwr a= ntohl(sc->g_dst.s_addr);
522 1.1 hwr b= a & 0x01;
523 1.1 hwr c= a & 0xfffffffe;
524 1.1 hwr b = b ^ 0x01;
525 1.1 hwr a = b | c;
526 1.1 hwr ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr=htonl(a);
527 1.1 hwr
528 1.1 hwr #ifdef DIAGNOSTIC
529 1.1 hwr printf("%s: searching a route to ",sc->sc_if.if_xname);
530 1.3 hwr gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
531 1.1 hwr #endif
532 1.1 hwr
533 1.1 hwr rtalloc(ro);
534 1.1 hwr
535 1.1 hwr /*
536 1.1 hwr * now change it back - else ip_output will just drop
537 1.1 hwr * the route and search one to this interface ...
538 1.1 hwr */
539 1.1 hwr ((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst;
540 1.1 hwr
541 1.1 hwr #ifdef DIAGNOSTIC
542 1.1 hwr printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
543 1.3 hwr gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
544 1.1 hwr printf("\n");
545 1.1 hwr #endif
546 1.1 hwr }
547 1.1 hwr
548 1.3 hwr /*
549 1.3 hwr * do a checksum of a buffer - much like in_cksum, which operates on
550 1.3 hwr * mbufs.
551 1.3 hwr */
552 1.3 hwr
553 1.3 hwr u_short
554 1.3 hwr gre_in_cksum(p, len)
555 1.3 hwr u_short *p;
556 1.3 hwr u_int len;
557 1.3 hwr {
558 1.3 hwr u_int sum = 0;
559 1.3 hwr int nwords = len >> 1;
560 1.3 hwr
561 1.3 hwr while (nwords-- != 0)
562 1.3 hwr sum += *p++;
563 1.3 hwr
564 1.3 hwr if (len & 1) {
565 1.3 hwr union {
566 1.3 hwr u_short w;
567 1.3 hwr u_char c[2];
568 1.3 hwr } u;
569 1.3 hwr u.c[0] = *(u_char *)p;
570 1.3 hwr u.c[1] = 0;
571 1.3 hwr sum += u.w;
572 1.3 hwr }
573 1.3 hwr
574 1.3 hwr /* end-around-carry */
575 1.3 hwr sum = (sum >> 16) + (sum & 0xffff);
576 1.3 hwr sum += (sum >> 16);
577 1.3 hwr return (~sum);
578 1.3 hwr }
579 1.3 hwr
580 1.3 hwr
581 1.1 hwr /* while testing ... */
582 1.1 hwr #ifdef DIAGNOSTIC
583 1.1 hwr void
584 1.3 hwr gre_inet_ntoa(in)
585 1.1 hwr struct in_addr in;
586 1.1 hwr {
587 1.1 hwr register char *p;
588 1.1 hwr
589 1.1 hwr p = (char *)∈
590 1.1 hwr #define UC(b) (((int)b)&0xff)
591 1.1 hwr printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
592 1.1 hwr }
593 1.1 hwr
594 1.1 hwr #endif
595 1.1 hwr #endif
596 1.1 hwr
597