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