xref: /original-bsd/sbin/routed/input.c (revision a0a7d8f4)
1 #ifndef lint
2 static char sccsid[] = "@(#)input.c	4.11 (Berkeley) 02/25/85";
3 #endif
4 
5 /*
6  * Routing Table Management Daemon
7  */
8 #include "defs.h"
9 
10 /*
11  * Process a newly received packet.
12  */
13 rip_input(from, size)
14 	struct sockaddr *from;
15 	int size;
16 {
17 	struct rt_entry *rt;
18 	struct netinfo *n;
19 	struct interface *ifp, *if_ifwithdstaddr();
20 	int newsize;
21 	struct afswitch *afp;
22 
23 	ifp = 0;
24 	TRACE_INPUT(ifp, from, size);
25 	if (from->sa_family >= AF_MAX)
26 		return;
27 	afp = &afswitch[from->sa_family];
28 	switch (msg->rip_cmd) {
29 
30 	case RIPCMD_REQUEST:
31 		newsize = 0;
32 		size -= 4 * sizeof (char);
33 		n = msg->rip_nets;
34 		while (size > 0) {
35 			if (size < sizeof (struct netinfo))
36 				break;
37 			size -= sizeof (struct netinfo);
38 
39 			if (msg->rip_vers > 0) {
40 				n->rip_dst.sa_family =
41 					ntohs(n->rip_dst.sa_family);
42 				n->rip_metric = ntohl(n->rip_metric);
43 			}
44 			/*
45 			 * A single entry with sa_family == AF_UNSPEC and
46 			 * metric ``infinity'' means ``all routes''.
47 			 */
48 			if (n->rip_dst.sa_family == AF_UNSPEC &&
49 			    n->rip_metric == HOPCNT_INFINITY && size == 0) {
50 				supply(from, 0, ifp);
51 				return;
52 			}
53 			rt = rtlookup(&n->rip_dst);
54 			n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
55 				min(rt->rt_metric+1, HOPCNT_INFINITY);
56 			if (msg->rip_vers > 0) {
57 				n->rip_dst.sa_family =
58 					htons(n->rip_dst.sa_family);
59 				n->rip_metric = htonl(n->rip_metric);
60 			}
61 			n++, newsize += sizeof (struct netinfo);
62 		}
63 		if (newsize > 0) {
64 			msg->rip_cmd = RIPCMD_RESPONSE;
65 			newsize += sizeof (int);
66 			(*afp->af_output)(s, 0, from, newsize);
67 		}
68 		return;
69 
70 	case RIPCMD_TRACEON:
71 	case RIPCMD_TRACEOFF:
72 		/* verify message came from a privileged port */
73 		if ((*afp->af_portcheck)(from) == 0)
74 			return;
75 		packet[size] = '\0';
76 		if (msg->rip_cmd == RIPCMD_TRACEON)
77 			traceon(msg->rip_tracefile);
78 		else
79 			traceoff();
80 		return;
81 
82 	case RIPCMD_RESPONSE:
83 		/* verify message came from a router */
84 		if ((*afp->af_portmatch)(from) == 0)
85 			return;
86 		(*afp->af_canon)(from);
87 		/* are we talking to ourselves? */
88 		ifp = if_ifwithaddr(from);
89 		if (ifp) {
90 			rt = rtfind(from);
91 			if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0)
92 				addrouteforif(ifp);
93 			else
94 				rt->rt_timer = 0;
95 			return;
96 		}
97 		/*
98 		 * Update timer for interface on which the packet arrived.
99 		 * If from other end of a point-to-point link that isn't
100 		 * in the routing tables, (re-)add the route.
101 		 */
102 		if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE))
103 			rt->rt_timer = 0;
104 		else if (ifp = if_ifwithdstaddr(from))
105 			addrouteforif(ifp);
106 		size -= 4 * sizeof (char);
107 		n = msg->rip_nets;
108 		for (; size > 0; size -= sizeof (struct netinfo), n++) {
109 			if (size < sizeof (struct netinfo))
110 				break;
111 			if (msg->rip_vers > 0) {
112 				n->rip_dst.sa_family =
113 					ntohs(n->rip_dst.sa_family);
114 				n->rip_metric = ntohl(n->rip_metric);
115 			}
116 			if ((unsigned) n->rip_metric >= HOPCNT_INFINITY)
117 				continue;
118 			if (n->rip_dst.sa_family >= AF_MAX)
119 				continue;
120 			afp = &afswitch[n->rip_dst.sa_family];
121 			if (((*afp->af_checkhost)(&n->rip_dst)) == 0)
122 				continue;
123 			rt = rtlookup(&n->rip_dst);
124 			if (rt == 0) {
125 				rtadd(&n->rip_dst, from, n->rip_metric, 0);
126 				continue;
127 			}
128 
129 			/*
130 			 * Update if from gateway and different,
131 			 * shorter, or getting stale and equivalent.
132 			 */
133 			if (equal(from, &rt->rt_router)) {
134 				if (n->rip_metric != rt->rt_metric)
135 					rtchange(rt, from, n->rip_metric);
136 				rt->rt_timer = 0;
137 			} else if ((unsigned) (n->rip_metric) < rt->rt_metric ||
138 			    (rt->rt_timer > (EXPIRE_TIME/2) &&
139 			    rt->rt_metric == n->rip_metric)) {
140 				rtchange(rt, from, n->rip_metric);
141 				rt->rt_timer = 0;
142 			}
143 		}
144 		return;
145 	}
146 }
147