1 /* route.c 4.11 82/06/20 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/protosw.h" 7 #include "../h/socket.h" 8 #include "../h/ioctl.h" 9 #include "../net/in.h" 10 #include "../net/in_systm.h" 11 #include "../net/if.h" 12 #include "../net/af.h" 13 #include "../net/route.h" 14 #include <errno.h> 15 16 int rttrash; /* routes not in table but not freed */ 17 /* 18 * Packet routing routines. 19 */ 20 rtalloc(ro) 21 register struct route *ro; 22 { 23 register struct rtentry *rt, *rtmin; 24 register struct mbuf *m; 25 register int hash, (*match)(); 26 struct afhash h; 27 struct sockaddr *dst = &ro->ro_dst; 28 int af = dst->sa_family; 29 30 if (ro->ro_rt && ro->ro_rt->rt_ifp) /* XXX */ 31 return; 32 if (af >= AF_MAX) 33 return; 34 (*afswitch[af].af_hash)(dst, &h); 35 rtmin = 0, hash = h.afh_hosthash; 36 for (m = rthost[hash % RTHASHSIZ]; m; m = m->m_next) { 37 rt = mtod(m, struct rtentry *); 38 if (rt->rt_hash != hash) 39 continue; 40 if ((rt->rt_flags & RTF_UP) == 0 || 41 (rt->rt_ifp->if_flags & IFF_UP) == 0) 42 continue; 43 if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst, sizeof (*dst))) 44 continue; 45 if (rtmin == 0 || rt->rt_use < rtmin->rt_use) 46 rtmin = rt; 47 } 48 if (rtmin) 49 goto found; 50 51 hash = h.afh_nethash; 52 match = afswitch[af].af_netmatch; 53 for (m = rtnet[hash % RTHASHSIZ]; m; m = m->m_next) { 54 rt = mtod(m, struct rtentry *); 55 if (rt->rt_hash != hash) 56 continue; 57 if ((rt->rt_flags & RTF_UP) == 0 || 58 (rt->rt_ifp->if_flags & IFF_UP) == 0) 59 continue; 60 if (rt->rt_dst.sa_family != af || !(*match)(&rt->rt_dst, dst)) 61 continue; 62 if (rtmin == 0 || rt->rt_use < rtmin->rt_use) 63 rtmin = rt; 64 } 65 found: 66 ro->ro_rt = rtmin; 67 if (rtmin) 68 rtmin->rt_refcnt++; 69 } 70 71 rtfree(rt) 72 register struct rtentry *rt; 73 { 74 register struct mbuf **mp; 75 76 if (rt == 0) 77 panic("freeroute"); 78 rt->rt_refcnt--; 79 if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) { 80 rttrash--; 81 (void) m_free(dtom(rt)); 82 } 83 } 84 85 /* 86 * Carry out a request to change the routing table. Called by 87 * interfaces at boot time to make their ``local routes'' known 88 * and for ioctl's. 89 */ 90 rtrequest(req, entry) 91 int req; 92 register struct rtentry *entry; 93 { 94 register struct mbuf *m, **mprev; 95 register struct rtentry *rt; 96 struct afhash h; 97 int af, s, error = 0, hash, (*match)(); 98 struct ifnet *ifp; 99 100 af = entry->rt_dst.sa_family; 101 if (af >= AF_MAX) 102 return (EAFNOSUPPORT); 103 (*afswitch[af].af_hash)(&entry->rt_dst, &h); 104 if (entry->rt_flags & RTF_HOST) { 105 hash = h.afh_hosthash; 106 mprev = &rthost[hash % RTHASHSIZ]; 107 } else { 108 hash = h.afh_nethash; 109 mprev = &rtnet[hash % RTHASHSIZ]; 110 } 111 match = afswitch[af].af_netmatch; 112 s = splimp(); 113 for (; m = *mprev; mprev = &m->m_next) { 114 rt = mtod(m, struct rtentry *); 115 if (rt->rt_hash != hash) 116 continue; 117 if (entry->rt_flags & RTF_HOST) { 118 #define equal(a1, a2) \ 119 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) 120 if (!equal(&rt->rt_dst, &entry->rt_dst)) 121 continue; 122 } else { 123 if (rt->rt_dst.sa_family != entry->rt_dst.sa_family || 124 (*match)(&rt->rt_dst, &entry->rt_dst) == 0) 125 continue; 126 } 127 if (equal(&rt->rt_gateway, &entry->rt_gateway)) 128 break; 129 } 130 switch (req) { 131 132 case SIOCDELRT: 133 if (m == 0) { 134 error = ESRCH; 135 goto bad; 136 } 137 *mprev = m->m_next; 138 if (rt->rt_refcnt > 0) { 139 rt->rt_flags &= ~RTF_UP; 140 rttrash++; 141 m->m_next = 0; 142 } else 143 (void) m_free(m); 144 break; 145 146 case SIOCADDRT: 147 if (m) { 148 error = EEXIST; 149 goto bad; 150 } 151 ifp = if_ifwithaddr(&entry->rt_gateway); 152 if (ifp == 0) { 153 ifp = if_ifwithnet(&entry->rt_gateway); 154 if (ifp == 0) { 155 error = ENETUNREACH; 156 goto bad; 157 } 158 } 159 m = m_get(M_DONTWAIT); 160 if (m == 0) { 161 error = ENOBUFS; 162 goto bad; 163 } 164 *mprev = m; 165 m->m_off = MMINOFF; 166 m->m_len = sizeof (struct rtentry); 167 rt = mtod(m, struct rtentry *); 168 rt->rt_hash = hash; 169 rt->rt_dst = entry->rt_dst; 170 rt->rt_gateway = entry->rt_gateway; 171 rt->rt_flags = 172 RTF_UP | (entry->rt_flags & (RTF_HOST|RTF_GATEWAY)); 173 rt->rt_refcnt = 0; 174 rt->rt_use = 0; 175 rt->rt_ifp = ifp; 176 break; 177 } 178 bad: 179 splx(s); 180 return (error); 181 } 182 183 /* 184 * Set up a routing table entry, normally 185 * for an interface. 186 */ 187 rtinit(dst, gateway, flags) 188 struct sockaddr *dst, *gateway; 189 int flags; 190 { 191 struct rtentry route; 192 struct route ro; 193 194 bzero((caddr_t)&route, sizeof (route)); 195 route.rt_dst = *dst; 196 route.rt_gateway = *gateway; 197 route.rt_flags = flags; 198 (void) rtrequest(SIOCADDRT, &route); 199 } 200