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