1*25202Skarels #ifdef	RCSIDENT
2*25202Skarels static char rcsident[] = "$Header: ip_output.c,v 1.28 85/07/31 09:32:09 walsh Exp $";
3*25202Skarels #endif
4*25202Skarels 
5*25202Skarels #include "../h/param.h"
6*25202Skarels #include "../h/dir.h"
7*25202Skarels #include "../h/user.h"
8*25202Skarels #include "../h/mbuf.h"
9*25202Skarels #include "../h/socket.h"
10*25202Skarels #include "../h/socketvar.h"
11*25202Skarels #include "../h/protosw.h"
12*25202Skarels #include "../h/domain.h"
13*25202Skarels #include "../h/ioctl.h"
14*25202Skarels #include "../h/syslog.h"
15*25202Skarels 
16*25202Skarels #include "../net/if.h"
17*25202Skarels #include "../net/route.h"
18*25202Skarels 
19*25202Skarels #include "../bbnnet/in.h"
20*25202Skarels #include "../bbnnet/net.h"
21*25202Skarels #include "../bbnnet/in_pcb.h"
22*25202Skarels #include "../bbnnet/in_var.h"
23*25202Skarels #include "../bbnnet/ip.h"
24*25202Skarels #include "../bbnnet/icmp.h"
25*25202Skarels 
26*25202Skarels /*
27*25202Skarels  * If you're going to a specific host or via a gateway, the routing
28*25202Skarels  * entry gateway field holds the best way to get there.  Otherwise,
29*25202Skarels  * the routing entry tells you how to get onto that net -- it has
30*25202Skarels  * the net address portion of our local host:
31*25202Skarels  *
32*25202Skarels  * On bbn-labs-b:
33*25202Skarels  *
34*25202Skarels  *		rt_dst		rt_gateway	flags
35*25202Skarels  * il0  => 	0x00000b80	0x2010b80	UP
36*25202Skarels  * imp0 =>	0x00000008	0x2000708	UP
37*25202Skarels  * loop =>	0x0000007f	0x100007f	UP
38*25202Skarels  *
39*25202Skarels  * So you can see that the rt_gateway is our local address, and the
40*25202Skarels  * rt_dst may be the net number of the media.  If it's a route
41*25202Skarels  * to a net, the other guy is on this net and you want to route the
42*25202Skarels  * packet to him anyway.
43*25202Skarels  *
44*25202Skarels  * gateway	0               0x1000b80       UP, RTF_GATEWAY
45*25202Skarels  */
46*25202Skarels 
47*25202Skarels #define IF_SEND(ifp, mp, rt, retval) \
48*25202Skarels {\
49*25202Skarels     static struct sockaddr_in tmproute = {AF_INET};                           \
50*25202Skarels \
51*25202Skarels     if (! ((ifp)->if_flags & IFF_UP)){					      \
52*25202Skarels 	/* goes with PRC_IFDOWN in in.c */				      \
53*25202Skarels 	m_freem(mp);							      \
54*25202Skarels 	retval = ENETUNREACH;						      \
55*25202Skarels     } else if ((rt)->rt_flags & (RTF_GATEWAY|RTF_HOST))                       \
56*25202Skarels 	retval = (*(ifp)->if_output)(ifp, mp, &(rt)->rt_gateway);             \
57*25202Skarels     else {                                                                    \
58*25202Skarels 	tmproute.sin_addr.s_addr = (mtod(mp, struct ip *))->ip_dst.s_addr;    \
59*25202Skarels 	retval = (*(ifp)->if_output)(ifp, mp, (struct sockaddr *) &tmproute); \
60*25202Skarels }}
61*25202Skarels 
62*25202Skarels if_send(ifp, mp, rt)
63*25202Skarels register struct ifnet *ifp;
64*25202Skarels register struct mbuf *mp;
65*25202Skarels register struct rtentry *rt;
66*25202Skarels {
67*25202Skarels     int	retval;
68*25202Skarels 
69*25202Skarels     IF_SEND (ifp, mp, rt, retval);
70*25202Skarels     return (retval);
71*25202Skarels }
72*25202Skarels 
73*25202Skarels 
74*25202Skarels /*
75*25202Skarels  * Find a route to this destination.  Given the source and destination
76*25202Skarels  * addresses, it returns a local net address
77*25202Skarels  * to send to (either the address of the destination itself or a gateway).
78*25202Skarels  * Taken mostly from rtalloc;  expanded to route according to
79*25202Skarels  * both ends of the connection.
80*25202Skarels  */
81*25202Skarels 
82*25202Skarels 
83*25202Skarels struct rtentry *ip_route(src, dst)
84*25202Skarels struct in_addr *src;
85*25202Skarels struct in_addr *dst;
86*25202Skarels {
87*25202Skarels     register struct rtentry *rt;
88*25202Skarels     register struct mbuf *m;
89*25202Skarels     register unsigned hash;
90*25202Skarels     net_t snet, dnet;
91*25202Skarels     int doinghost;
92*25202Skarels     struct rtentry *rtmin;
93*25202Skarels     struct mbuf **table;
94*25202Skarels     static struct in_addr wildcard;
95*25202Skarels 
96*25202Skarels     /* get network parts of src and dest addresses */
97*25202Skarels 
98*25202Skarels     snet = iptonet(*src);
99*25202Skarels     dnet = iptonet(*dst);
100*25202Skarels 
101*25202Skarels     rtmin = NULL;
102*25202Skarels     hash = HOSTHASH(dst->s_addr);
103*25202Skarels     table = rthost;
104*25202Skarels     doinghost = TRUE;
105*25202Skarels again :
106*25202Skarels     for (m = table[hash % RTHASHSIZ]; m; m = m->m_next)
107*25202Skarels     {
108*25202Skarels 	rt = mtod(m, struct rtentry *);
109*25202Skarels 	if (rt->rt_hash != hash)
110*25202Skarels 	    continue;
111*25202Skarels 	if (! (rt->rt_flags & RTF_UP))
112*25202Skarels 	    continue;
113*25202Skarels 	if (! (rt->rt_ifp->if_flags & IFF_UP))
114*25202Skarels 	    continue;
115*25202Skarels 	if (rt->rt_dst.sa_family != AF_INET)
116*25202Skarels 	    continue;
117*25202Skarels 
118*25202Skarels 	/* packets go out an interface with our local IP address */
119*25202Skarels 	if (iptonet(((struct sockaddr_in *)&(rt->rt_gateway))->sin_addr) != snet)
120*25202Skarels 	    continue;
121*25202Skarels 
122*25202Skarels 	/* does this route get us there? */
123*25202Skarels 	if (doinghost)
124*25202Skarels 	{
125*25202Skarels 	    if (((struct sockaddr_in *)&(rt->rt_dst))->sin_addr.s_addr !=
126*25202Skarels 		dst->s_addr)
127*25202Skarels 		continue;
128*25202Skarels 	}
129*25202Skarels 	else
130*25202Skarels 	{
131*25202Skarels 	    /*
132*25202Skarels 	     * iptonet == 0 => smart gateway (route to anywhere)
133*25202Skarels 	     * iptonet != 0 => gateway to another net (route to net)
134*25202Skarels 	     */
135*25202Skarels 	    if (iptonet(((struct sockaddr_in *)&(rt->rt_dst))->sin_addr) != dnet)
136*25202Skarels 		continue;
137*25202Skarels 	}
138*25202Skarels 
139*25202Skarels 	/* and try to share load across gateways */
140*25202Skarels 	if (rtmin == NULL)
141*25202Skarels 	    rtmin = rt;
142*25202Skarels 	else if (rt->rt_use < rtmin->rt_use)
143*25202Skarels 	    rtmin = rt;
144*25202Skarels     }
145*25202Skarels 
146*25202Skarels     if (rtmin == NULL)
147*25202Skarels     {
148*25202Skarels 	if (doinghost)
149*25202Skarels 	{
150*25202Skarels 	    doinghost = FALSE;
151*25202Skarels 	    hash = NETHASH(*dst), table = rtnet;
152*25202Skarels 	    goto again;
153*25202Skarels 	}
154*25202Skarels 	/*
155*25202Skarels 	 * Check for wildcard gateway, by convention network 0.
156*25202Skarels 	 */
157*25202Skarels 	if (dst != &wildcard)
158*25202Skarels 	{
159*25202Skarels 	    hash = 0;
160*25202Skarels 	    dst = &wildcard;
161*25202Skarels 	    dnet = 0;
162*25202Skarels 	    goto again;
163*25202Skarels 	}
164*25202Skarels 	rtstat.rts_unreach++;
165*25202Skarels 	return(NULL);
166*25202Skarels     }
167*25202Skarels 
168*25202Skarels     rtmin->rt_refcnt++;
169*25202Skarels     if (dst == &wildcard)
170*25202Skarels 	rtstat.rts_wildcard++;
171*25202Skarels     return(rtmin);
172*25202Skarels }
173*25202Skarels 
174*25202Skarels 
175*25202Skarels /*
176*25202Skarels  * Ip_send is called from the higher protocol layer (TCP/RDP/UDP) and is passed
177*25202Skarels  * an mbuf chain containing a packet to send to the local network.  The first
178*25202Skarels  * mbuf contains the protocol header and an IP header which is partially
179*25202Skarels  * filled in.  After determining a route (outgoing interface + first hop) for
180*25202Skarels  * the packet, it is fragmented (if necessary) and sent to the local net
181*25202Skarels  * through the local net send routine.
182*25202Skarels  *
183*25202Skarels  * For non-raw output, caller should have stuffed:
184*25202Skarels  *	ip protocol type, type of service, source addr, destin addr
185*25202Skarels  *
186*25202Skarels  * ip_tos is left to caller so that people using raw sockets can do whatever
187*25202Skarels  * they please.  (They don't have an inpcb in which to store such info.)
188*25202Skarels  *
189*25202Skarels  * The asis argument is TRUE for raw output and the gateway (packet forwarding)
190*25202Skarels  * code.  It indicates that the IP header is fully constructed.
191*25202Skarels  *
192*25202Skarels  * Errors at the IP layer and below occur synchronously, and can be reported
193*25202Skarels  * back via subroutine return values.  Higher level protocols should remember
194*25202Skarels  * that if they do things asynchronous to a system call (ie., packet
195*25202Skarels  * retransmission) that they should post error back to user via advise_user()
196*25202Skarels  * so that user gets error next time he rendezvous with the kernel.
197*25202Skarels  */
198*25202Skarels ip_send(inp, mp, len, asis)
199*25202Skarels struct inpcb *inp;
200*25202Skarels register struct mbuf *mp;
201*25202Skarels register int len;
202*25202Skarels int asis;
203*25202Skarels {
204*25202Skarels     register struct ip *p;
205*25202Skarels     register struct ifnet *ifp;
206*25202Skarels     register struct rtentry *rt;
207*25202Skarels     register int hlen;
208*25202Skarels     int free_route = FALSE;
209*25202Skarels     int retval;
210*25202Skarels 
211*25202Skarels     p = mtod(mp, struct ip *);	/* -> ip header */
212*25202Skarels     /*
213*25202Skarels      * Find route for datagram if one has not been assigned.
214*25202Skarels      */
215*25202Skarels     if ((rt = inp->inp_route.ro_rt) == NULL)
216*25202Skarels     {
217*25202Skarels 	if ((rt = ip_route(&p->ip_src, &p->ip_dst)) == NULL)
218*25202Skarels 	{
219*25202Skarels 	    if (asis || (p->ip_src.s_addr == INADDR_ANY))
220*25202Skarels 	    {
221*25202Skarels 		/*
222*25202Skarels 		 * asis: forwarding a packet not sourced by us
223*25202Skarels 		 *      eg., by raw interface and user level repeater process
224*25202Skarels 		 * INADDR_ANY: sending icmp packet for which
225*25202Skarels 		 *      we're trying to avoid routing twice.
226*25202Skarels 		 */
227*25202Skarels 		struct route tmproute;
228*25202Skarels 		struct sockaddr_in *sin;
229*25202Skarels 
230*25202Skarels 		bzero ((caddr_t) &tmproute, sizeof(tmproute));
231*25202Skarels 		sin = (struct sockaddr_in *) &tmproute.ro_dst;
232*25202Skarels 		sin->sin_family = AF_INET;
233*25202Skarels 		sin->sin_addr.s_addr = p->ip_dst.s_addr;
234*25202Skarels 		rtalloc (&tmproute);
235*25202Skarels 		rt = tmproute.ro_rt;
236*25202Skarels 
237*25202Skarels 		if (rt && (p->ip_src.s_addr == INADDR_ANY))
238*25202Skarels 		    p->ip_src = IA_INADDR(in_iafromif(rt->rt_ifp));
239*25202Skarels 	    }
240*25202Skarels 
241*25202Skarels 	    if (rt == NULL)
242*25202Skarels 	    {
243*25202Skarels 		m_freem(mp);
244*25202Skarels 		return(ENETUNREACH);
245*25202Skarels 	    }
246*25202Skarels 	}
247*25202Skarels 	free_route = TRUE;
248*25202Skarels     }
249*25202Skarels     ifp = rt->rt_ifp;
250*25202Skarels 
251*25202Skarels     /*
252*25202Skarels      * Copy ip source route to header.  Know asis must be FALSE, if do.
253*25202Skarels      */
254*25202Skarels     if (inp->inp_optlen > 0)
255*25202Skarels     {
256*25202Skarels 	char	*q;
257*25202Skarels 
258*25202Skarels 	if (mp->m_off - inp->inp_optlen >= MMINOFF)
259*25202Skarels 	{
260*25202Skarels 	    struct in_addr *ipa;
261*25202Skarels 
262*25202Skarels 	    mp->m_off -= inp->inp_optlen;
263*25202Skarels 	    mp->m_len += inp->inp_optlen;
264*25202Skarels 	    q = (char *) p;
265*25202Skarels 	    p = (struct ip *) (q - inp->inp_optlen);
266*25202Skarels 	    bcopy(q, (caddr_t)p, sizeof(struct ip));
267*25202Skarels 	    bcopy(inp->inp_options, (caddr_t)(p+1), (unsigned)inp->inp_optlen);
268*25202Skarels 	    /*
269*25202Skarels 	     * And replate eventual destination with first hop.
270*25202Skarels 	     * Eventual destination is in source route just
271*25202Skarels 	     * copied in.
272*25202Skarels 	     */
273*25202Skarels 	    ipa = (struct in_addr *) (&inp->inp_options[0]);
274*25202Skarels 	    p->ip_dst = ipa[inp->inp_optlen/sizeof(struct in_addr)];
275*25202Skarels 	}
276*25202Skarels 	else
277*25202Skarels 	    log(KERN_RECOV, "ip_send: optlen %d inpcb 0x%x\n",
278*25202Skarels 		(int)inp->inp_optlen, inp);
279*25202Skarels     }
280*25202Skarels 
281*25202Skarels     /*
282*25202Skarels      * fill in ip header fields
283*25202Skarels      */
284*25202Skarels     if (asis)
285*25202Skarels     {
286*25202Skarels 	/*
287*25202Skarels 	 * RAW OUTPUT.  Must get len, hlen, off from packet header.
288*25202Skarels 	 * Byte swap is ugly (since we must swap back below), but
289*25202Skarels 	 * necessary in case we must fragment.
290*25202Skarels 	 */
291*25202Skarels 	hlen = p->ip_hl << IP_HLSHIFT;
292*25202Skarels 	len = ntohs(p->ip_len);
293*25202Skarels 	p->ip_off = ntohs(p->ip_off);
294*25202Skarels     }
295*25202Skarels     else
296*25202Skarels     {
297*25202Skarels 	static u_short next_ip_id; /* some day RDP may want to force for rxmit */
298*25202Skarels 
299*25202Skarels 	hlen = sizeof(struct ip) + inp->inp_optlen;
300*25202Skarels 	len += hlen;
301*25202Skarels 	p->ip_v = IPVERSION;
302*25202Skarels 	p->ip_hl = hlen >> IP_HLSHIFT;
303*25202Skarels 	p->ip_off = 0;
304*25202Skarels 	p->ip_ttl = MAXTTL; /* ### should come from route */
305*25202Skarels 	p->ip_id = htons(next_ip_id++);
306*25202Skarels     }
307*25202Skarels 
308*25202Skarels     /*
309*25202Skarels      * let ip_frag do the send if needed, otherwise do it directly.
310*25202Skarels      */
311*25202Skarels 
312*25202Skarels     /* for testing IP reassembly code */
313*25202Skarels #ifdef FORCE_FRAG
314*25202Skarels #define MTU(ifp) (((ifp)->if_mtu >> FORCE_FRAG) & (~3))
315*25202Skarels #else
316*25202Skarels #define MTU(ifp) (ifp)->if_mtu
317*25202Skarels #endif
318*25202Skarels 
319*25202Skarels     if (len > MTU(ifp))
320*25202Skarels     {
321*25202Skarels 	p->ip_len = len;
322*25202Skarels 	retval = ip_frag(p, ifp, rt, hlen);
323*25202Skarels     }
324*25202Skarels     else
325*25202Skarels     {
326*25202Skarels 	/*
327*25202Skarels 	 * complete header, byte swap, and send to local net
328*25202Skarels 	 */
329*25202Skarels 	p->ip_len = htons((u_short)len);
330*25202Skarels 	p->ip_off = htons(p->ip_off);
331*25202Skarels 	/*
332*25202Skarels 	 * No reason not to have kernel checksum, even for raw packets.
333*25202Skarels 	 */
334*25202Skarels 	p->ip_sum = 0;
335*25202Skarels 	p->ip_sum = in_cksum(dtom(p), hlen);
336*25202Skarels 	IF_SEND (ifp, mp, rt, retval);
337*25202Skarels     }
338*25202Skarels 
339*25202Skarels     rt->rt_use ++;	/* Yet another IP packet sent away */
340*25202Skarels 
341*25202Skarels     if (free_route)
342*25202Skarels     {
343*25202Skarels 	struct socket *so;
344*25202Skarels 
345*25202Skarels 	if ((so = inp->inp_socket) &&
346*25202Skarels 	    (so->so_proto->pr_flags & PR_CONNREQUIRED))
347*25202Skarels 	    /*
348*25202Skarels 	     * Found a new route after old one pinged out.
349*25202Skarels 	     */
350*25202Skarels 	    inp->inp_route.ro_rt = rt;
351*25202Skarels 	else
352*25202Skarels 	    rtfree(rt);
353*25202Skarels     }
354*25202Skarels 
355*25202Skarels     return(retval);
356*25202Skarels }
357*25202Skarels 
358*25202Skarels /*
359*25202Skarels  * Ip_frag is called with a packet with a completed ip header
360*25202Skarels  * (except for checksum).  It fragments the packet, inserts the
361*25202Skarels  * IP checksum, and calls the appropriate local net output routine
362*25202Skarels  * to send it to the net.
363*25202Skarels  *
364*25202Skarels  * Previously, when there was only one kind of mbuf, it tried to
365*25202Skarels  * reduce space requirements by recycling the chain to be fragmented.
366*25202Skarels  * Preserving this approach is overly complicated, and should mbufs
367*25202Skarels  * change again, cause problems.  Therefore, have switched to copying
368*25202Skarels  * the chain to be fragmented.
369*25202Skarels  */
370*25202Skarels ip_frag(p, ifp, rt, hlen)
371*25202Skarels register struct ip *p;
372*25202Skarels struct ifnet *ifp;
373*25202Skarels struct rtentry *rt;
374*25202Skarels register int hlen;
375*25202Skarels {
376*25202Skarels     register struct mbuf *m;	/* original chunk */
377*25202Skarels     register struct mbuf *mhdr;	/* fragment */
378*25202Skarels     register struct ip *fip;	/* the fragment IP header */
379*25202Skarels     int off;	/* offset into entire IP datagram */
380*25202Skarels     int here;	/* offset into this chunk of it */
381*25202Skarels     register int len;	/* length of data in this chunk */
382*25202Skarels     int flags;	/* of this chunk to fragment */
383*25202Skarels     int max;	/* max data length in a fragment */
384*25202Skarels     int fdlen;	/* actual fragment data length */
385*25202Skarels     int error;
386*25202Skarels 
387*25202Skarels     m = dtom(p);
388*25202Skarels 
389*25202Skarels     if (p->ip_off & ip_df)
390*25202Skarels     {	/* can't fragment */
391*25202Skarels 	m_freem(m);
392*25202Skarels 	return(EMSGSIZE);
393*25202Skarels     }
394*25202Skarels     max = MTU(ifp) - hlen;	/* max data length in frag */
395*25202Skarels     len = p->ip_len - hlen;	/* data length */
396*25202Skarels 
397*25202Skarels     /*
398*25202Skarels      * this only needs to be this complicated if we are handed
399*25202Skarels      * an already-fragmented packet
400*25202Skarels      */
401*25202Skarels     flags	= p->ip_off&(ip_mf|ip_df);	/* save old flags */
402*25202Skarels     p->ip_off &= ~flags;	/* take them out of ip_off */
403*25202Skarels     off	= p->ip_off << IP_OFFSHIFT;	/* fragment offset */
404*25202Skarels     here	= hlen;
405*25202Skarels     error	= 0;
406*25202Skarels 
407*25202Skarels     while (len > 0)
408*25202Skarels     {
409*25202Skarels 	/*
410*25202Skarels 	 * Allocate mbuf for fragment IP header
411*25202Skarels 	 */
412*25202Skarels 	mhdr = m_get(M_DONTWAIT, MT_HEADER);
413*25202Skarels 	if (mhdr == NULL)
414*25202Skarels 	{
415*25202Skarels 	    error = ENOBUFS;
416*25202Skarels 	    break;
417*25202Skarels 	}
418*25202Skarels 	/*
419*25202Skarels 	 * get copy of data for fragment
420*25202Skarels 	 */
421*25202Skarels 	if (len < max)
422*25202Skarels 	    fdlen = len;
423*25202Skarels 	else
424*25202Skarels 	    fdlen = max & (~7); /* 7 == 2^IP_OFFSHIFT -1 */
425*25202Skarels 	mhdr->m_next = m_copy(m, here, fdlen);
426*25202Skarels 	if (mhdr->m_next == NULL)
427*25202Skarels 	{
428*25202Skarels 	    m_free(mhdr);
429*25202Skarels 	    error = ENOBUFS;
430*25202Skarels 	    break;
431*25202Skarels 	}
432*25202Skarels 	/*
433*25202Skarels 	 * build the header for this fragment and ship it off.
434*25202Skarels 	 */
435*25202Skarels 	mhdr->m_len = hlen;
436*25202Skarels 	mhdr->m_off = MMAXOFF - hlen;
437*25202Skarels 	fip = mtod(mhdr, struct ip *);
438*25202Skarels 	bcopy((caddr_t)p, (caddr_t)fip, (unsigned)hlen);
439*25202Skarels 	fip->ip_off = off >> IP_OFFSHIFT;
440*25202Skarels 	if (fdlen >= len)
441*25202Skarels 	    /* it's the last fragment */
442*25202Skarels 	    fip->ip_off |= flags;
443*25202Skarels 	else
444*25202Skarels 	    fip->ip_off |= ip_mf;
445*25202Skarels 	fip->ip_off = htons((u_short)fip->ip_off);
446*25202Skarels 	fip->ip_len = htons((u_short)fdlen + hlen);
447*25202Skarels 	fip->ip_sum = 0;
448*25202Skarels 	fip->ip_sum = in_cksum(mhdr, hlen);
449*25202Skarels 	if (error = if_send (ifp, mhdr, rt))
450*25202Skarels 	    break;
451*25202Skarels 
452*25202Skarels 	/*
453*25202Skarels 	 * and get ready for next pass through the loop
454*25202Skarels 	 */
455*25202Skarels 	len	-= fdlen;
456*25202Skarels 	off	+= fdlen;
457*25202Skarels 	here	+= fdlen;
458*25202Skarels     }
459*25202Skarels 
460*25202Skarels     m_freem(m);
461*25202Skarels     return (error);
462*25202Skarels }
463*25202Skarels 
464*25202Skarels /*
465*25202Skarels  * Current connection should use a new path.
466*25202Skarels  */
467*25202Skarels struct rtentry *ip_reroute(inp)
468*25202Skarels register struct inpcb *inp;
469*25202Skarels {
470*25202Skarels     register struct route *ro = &inp->inp_route;
471*25202Skarels 
472*25202Skarels     rtfree(ro->ro_rt);
473*25202Skarels     return(ro->ro_rt = ip_route(&inp->inp_laddr, &inp->inp_faddr));
474*25202Skarels }
475*25202Skarels 
476*25202Skarels /*
477*25202Skarels  * A gateway has gone down.  Change route used by all connections currently
478*25202Skarels  * using it.
479*25202Skarels  */
480*25202Skarels ip_gdown(addr)
481*25202Skarels u_long	addr;
482*25202Skarels {
483*25202Skarels     register struct protosw *psw;
484*25202Skarels 
485*25202Skarels     for(psw=inetdomain.dom_protosw; psw < inetdomain.dom_protoswNPROTOSW; psw++)
486*25202Skarels 	if (psw->pr_type != SOCK_RAW)
487*25202Skarels 		if (psw->pr_ctlinput)
488*25202Skarels 			(*(psw->pr_ctlinput)) (PRC_GWDOWN, addr);
489*25202Skarels }
490*25202Skarels 
491*25202Skarels /*
492*25202Skarels  * Called from protocol ctlinput routine.  This way, IP/ICMP don't need to know
493*25202Skarels  * about protocol's head of inpcbs... for all the protocols.
494*25202Skarels  */
495*25202Skarels in_gdown (head, addr)
496*25202Skarels register struct inpcb *head;
497*25202Skarels u_long addr;
498*25202Skarels {
499*25202Skarels     register struct inpcb   *inp;
500*25202Skarels     register struct rtentry *rt;
501*25202Skarels 
502*25202Skarels     if (head == NULL)
503*25202Skarels 	return;
504*25202Skarels 
505*25202Skarels     for(inp = head->inp_next; inp != head; inp = inp->inp_next)
506*25202Skarels     {
507*25202Skarels 	if (rt = inp->inp_route.ro_rt)
508*25202Skarels 	{
509*25202Skarels 	    if (rt->rt_flags & RTF_GATEWAY)
510*25202Skarels 	    {
511*25202Skarels 		if (((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr == addr)
512*25202Skarels 		{
513*25202Skarels 			/*
514*25202Skarels 			 * Don't remove route permanently, since want to catch
515*25202Skarels 			 * the gateway when it reboots:
516*25202Skarels 			 *      -- rtrequest (SIOCDELRT, rt) --
517*25202Skarels 			 *
518*25202Skarels 			 * make sure rtfree() not remove route mbuf
519*25202Skarels 			 * incrementing reference count here, and decrementing
520*25202Skarels 			 * when timeout on reinstatement goes off.  Cannot call
521*25202Skarels 			 * rtfree with zero reference count when have not done
522*25202Skarels 			 * SIOCDELRT.
523*25202Skarels 			 */
524*25202Skarels 			if (rt->rt_flags & RTF_UP)
525*25202Skarels 			{
526*25202Skarels 			    rt->rt_flags &= ~RTF_UP;
527*25202Skarels 			    rt->rt_flags |= RTF_REINSTATE;
528*25202Skarels 			    rt->irt_gdown = RT_REINSTATE;
529*25202Skarels 			    rt->rt_refcnt ++;
530*25202Skarels 			}
531*25202Skarels 
532*25202Skarels 			if (!ip_reroute(inp))
533*25202Skarels 			    advise_user(inp->inp_socket, ENETUNREACH);
534*25202Skarels 
535*25202Skarels 		}
536*25202Skarels 	    }
537*25202Skarels 	}
538*25202Skarels     }
539*25202Skarels }
540