1 /* 2 * Copyright (c) 1985 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This file includes significant work done at Cornell University by 6 * Bill Nesheim. That work included by permission. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 */ 20 21 #ifndef lint 22 static char sccsid[] = "@(#)input.c 5.8 (Berkeley) 08/21/89"; 23 #endif /* not lint */ 24 25 /* 26 * XNS Routing Table Management Daemon 27 */ 28 #include "defs.h" 29 30 struct sockaddr * 31 xns_nettosa(net) 32 union ns_net net; 33 { 34 static struct sockaddr_ns sxn; 35 extern char ether_broadcast_addr[6]; 36 37 bzero(&sxn, sizeof (struct sockaddr_ns)); 38 sxn.sns_family = AF_NS; 39 sxn.sns_len = sizeof (sxn); 40 sxn.sns_addr.x_net = net; 41 sxn.sns_addr.x_host = *(union ns_host *)ether_broadcast_addr; 42 return( (struct sockaddr *)&sxn); 43 44 } 45 46 /* 47 * Process a newly received packet. 48 */ 49 rip_input(from, size) 50 struct sockaddr *from; 51 int size; 52 { 53 struct rt_entry *rt; 54 struct netinfo *n; 55 struct interface *ifp; 56 int newsize; 57 struct afswitch *afp; 58 59 60 ifp = 0; 61 TRACE_INPUT(ifp, from, size); 62 if (from->sa_family >= AF_MAX) 63 return; 64 afp = &afswitch[from->sa_family]; 65 66 size -= sizeof (u_short) /* command */; 67 n = msg->rip_nets; 68 69 switch (ntohs(msg->rip_cmd)) { 70 71 case RIPCMD_REQUEST: 72 newsize = 0; 73 while (size > 0) { 74 if (size < sizeof (struct netinfo)) 75 break; 76 size -= sizeof (struct netinfo); 77 78 /* 79 * A single entry with rip_dst == DSTNETS_ALL and 80 * metric ``infinity'' means ``all routes''. 81 */ 82 if (ns_neteqnn(n->rip_dst, ns_anynet) && 83 ntohs(n->rip_metric) == HOPCNT_INFINITY && 84 size == 0) { 85 ifp = if_ifwithnet(from); 86 supply(from, 0, ifp); 87 return; 88 } 89 /* 90 * request for specific nets 91 */ 92 rt = rtlookup(xns_nettosa(n->rip_dst)); 93 if (ftrace) { 94 fprintf(ftrace, 95 "specific request for %s", 96 xns_nettoa(n->rip_dst)); 97 fprintf(ftrace, 98 " yields route %x\n", 99 rt); 100 } 101 n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY : 102 min(rt->rt_metric+1, HOPCNT_INFINITY)); 103 n++; 104 newsize += sizeof (struct netinfo); 105 } 106 if (newsize > 0) { 107 msg->rip_cmd = htons(RIPCMD_RESPONSE); 108 newsize += sizeof (u_short); 109 /* should check for if with dstaddr(from) first */ 110 (*afp->af_output)(0, from, newsize); 111 ifp = if_ifwithnet(from); 112 TRACE_OUTPUT(ifp, from, newsize); 113 if (ftrace) { 114 fprintf(ftrace, 115 "request arrived on interface %s\n", 116 ifp->int_name); 117 } 118 } 119 return; 120 121 case RIPCMD_RESPONSE: 122 /* verify message came from a router */ 123 if ((*afp->af_portmatch)(from) == 0) 124 return; 125 (*afp->af_canon)(from); 126 /* are we talking to ourselves? */ 127 if (ifp = if_ifwithaddr(from)) { 128 rt = rtfind(from); 129 if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) 130 addrouteforif(ifp); 131 else 132 rt->rt_timer = 0; 133 return; 134 } 135 /* Update timer for interface on which the packet arrived. 136 * If from other end of a point-to-point link that isn't 137 * in the routing tables, (re-)add the route. 138 */ 139 if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) { 140 if(ftrace) fprintf(ftrace, "Got route\n"); 141 rt->rt_timer = 0; 142 } else if (ifp = if_ifwithdstaddr(from)) { 143 if(ftrace) fprintf(ftrace, "Got partner\n"); 144 addrouteforif(ifp); 145 } 146 for (; size > 0; size -= sizeof (struct netinfo), n++) { 147 struct sockaddr *sa; 148 if (size < sizeof (struct netinfo)) 149 break; 150 if ((unsigned) ntohs(n->rip_metric) >= HOPCNT_INFINITY) 151 continue; 152 rt = rtfind(sa = xns_nettosa(n->rip_dst)); 153 if (rt == 0) { 154 rtadd(sa, from, ntohs(n->rip_metric), 0); 155 continue; 156 } 157 158 /* 159 * Update if from gateway and different, 160 * from anywhere and shorter, or getting stale and equivalent. 161 */ 162 if ((equal(from, &rt->rt_router) && 163 ntohs(n->rip_metric) != rt->rt_metric ) || 164 (unsigned) ntohs(n->rip_metric) < rt->rt_metric || 165 (rt->rt_timer > (EXPIRE_TIME/2) && 166 rt->rt_metric == ntohs(n->rip_metric))) { 167 rtchange(rt, from, ntohs(n->rip_metric)); 168 rt->rt_timer = 0; 169 } 170 } 171 return; 172 } 173 } 174