xref: /original-bsd/sbin/routed/output.c (revision b4971bb3)
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)output.c	8.1 (Berkeley) 06/05/93";
10 #endif /* not lint */
11 
12 /*
13  * Routing Table Management Daemon
14  */
15 #include "defs.h"
16 
17 /*
18  * Apply the function "f" to all non-passive
19  * interfaces.  If the interface supports the
20  * use of broadcasting use it, otherwise address
21  * the output to the known router.
22  */
23 toall(f, rtstate, skipif)
24 	int (*f)();
25 	int rtstate;
26 	struct interface *skipif;
27 {
28 	register struct interface *ifp;
29 	register struct sockaddr *dst;
30 	register int flags;
31 	extern struct interface *ifnet;
32 
33 	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
34 		if (ifp->int_flags & IFF_PASSIVE || ifp == skipif)
35 			continue;
36 		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
37 		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
38 		      &ifp->int_addr;
39 		flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
40 		(*f)(dst, flags, ifp, rtstate);
41 	}
42 }
43 
44 /*
45  * Output a preformed packet.
46  */
47 /*ARGSUSED*/
48 sndmsg(dst, flags, ifp, rtstate)
49 	struct sockaddr *dst;
50 	int flags;
51 	struct interface *ifp;
52 	int rtstate;
53 {
54 
55 	(*afswitch[dst->sa_family].af_output)(s, flags,
56 		dst, sizeof (struct rip));
57 	TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
58 }
59 
60 /*
61  * Supply dst with the contents of the routing tables.
62  * If this won't fit in one packet, chop it up into several.
63  */
64 supply(dst, flags, ifp, rtstate)
65 	struct sockaddr *dst;
66 	int flags;
67 	register struct interface *ifp;
68 	int rtstate;
69 {
70 	register struct rt_entry *rt;
71 	register struct netinfo *n = msg->rip_nets;
72 	register struct rthash *rh;
73 	struct rthash *base = hosthash;
74 	int doinghost = 1, size;
75 	int (*output)() = afswitch[dst->sa_family].af_output;
76 	int (*sendroute)() = afswitch[dst->sa_family].af_sendroute;
77 	int npackets = 0;
78 
79 	msg->rip_cmd = RIPCMD_RESPONSE;
80 	msg->rip_vers = RIPVERSION;
81 	bzero(msg->rip_res1, sizeof(msg->rip_res1));
82 again:
83 	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
84 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
85 		/*
86 		 * Don't resend the information on the network
87 		 * from which it was received (unless sending
88 		 * in response to a query).
89 		 */
90 		if (ifp && rt->rt_ifp == ifp &&
91 		    (rt->rt_state & RTS_INTERFACE) == 0)
92 			continue;
93 		if (rt->rt_state & RTS_EXTERNAL)
94 			continue;
95 		/*
96 		 * For dynamic updates, limit update to routes
97 		 * with the specified state.
98 		 */
99 		if (rtstate && (rt->rt_state & rtstate) == 0)
100 			continue;
101 		/*
102 		 * Limit the spread of subnet information
103 		 * to those who are interested.
104 		 */
105 		if (doinghost == 0 && rt->rt_state & RTS_SUBNET) {
106 			if (rt->rt_dst.sa_family != dst->sa_family)
107 				continue;
108 			if ((*sendroute)(rt, dst) == 0)
109 				continue;
110 		}
111 		size = (char *)n - packet;
112 		if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
113 			TRACE_OUTPUT(ifp, dst, size);
114 			(*output)(s, flags, dst, size);
115 			/*
116 			 * If only sending to ourselves,
117 			 * one packet is enough to monitor interface.
118 			 */
119 			if (ifp && (ifp->int_flags &
120 			   (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0)
121 				return;
122 			n = msg->rip_nets;
123 			npackets++;
124 		}
125 		n->rip_dst = rt->rt_dst;
126 #if BSD < 198810
127 		if (sizeof(n->rip_dst.sa_family) > 1)	/* XXX */
128 		n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
129 #else
130 #define osa(x) ((struct osockaddr *)(&(x)))
131 		osa(n->rip_dst)->sa_family = htons(n->rip_dst.sa_family);
132 #endif
133 		n->rip_metric = htonl(rt->rt_metric);
134 		n++;
135 	}
136 	if (doinghost) {
137 		doinghost = 0;
138 		base = nethash;
139 		goto again;
140 	}
141 	if (n != msg->rip_nets || (npackets == 0 && rtstate == 0)) {
142 		size = (char *)n - packet;
143 		TRACE_OUTPUT(ifp, dst, size);
144 		(*output)(s, flags, dst, size);
145 	}
146 }
147