| 1 | #ifndef lint |
| 2 | static char sccsid[] = "@(#)input.c 4.9 (Berkeley) %G%"; |
| 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; |
| 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 | /* update timer for interface on which the packet arrived */ |
| 98 | if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) |
| 99 | rt->rt_timer = 0; |
| 100 | size -= 4 * sizeof (char); |
| 101 | n = msg->rip_nets; |
| 102 | for (; size > 0; size -= sizeof (struct netinfo), n++) { |
| 103 | if (size < sizeof (struct netinfo)) |
| 104 | break; |
| 105 | if (msg->rip_vers > 0) { |
| 106 | n->rip_dst.sa_family = |
| 107 | ntohs(n->rip_dst.sa_family); |
| 108 | n->rip_metric = ntohl(n->rip_metric); |
| 109 | } |
| 110 | if ((unsigned) n->rip_metric >= HOPCNT_INFINITY) |
| 111 | continue; |
| 112 | if (n->rip_dst.sa_family >= AF_MAX) |
| 113 | continue; |
| 114 | afp = &afswitch[n->rip_dst.sa_family]; |
| 115 | if (((*afp->af_checkhost)(&n->rip_dst)) == 0) |
| 116 | continue; |
| 117 | rt = rtlookup(&n->rip_dst); |
| 118 | if (rt == 0) { |
| 119 | rtadd(&n->rip_dst, from, n->rip_metric, 0); |
| 120 | continue; |
| 121 | } |
| 122 | |
| 123 | /* |
| 124 | * Update if from gateway and different, |
| 125 | * shorter, or getting stale and equivalent. |
| 126 | */ |
| 127 | if ((equal(from, &rt->rt_router) && |
| 128 | n->rip_metric != rt->rt_metric ) || |
| 129 | (unsigned) (n->rip_metric) < rt->rt_metric || |
| 130 | (rt->rt_timer > (EXPIRE_TIME/2) && |
| 131 | rt->rt_metric == n->rip_metric)) { |
| 132 | rtchange(rt, from, n->rip_metric); |
| 133 | rt->rt_timer = 0; |
| 134 | } |
| 135 | } |
| 136 | return; |
| 137 | } |
| 138 | } |